﻿{ *
  * Copyright (C) 2012-2013 ozok <ozok26@gmail.com>
  *
  * This file is part of TAudioConverter.
  *
  * TAudioConverter is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 2 of the License, or
  * (at your option) any later version.
  *
  * TAudioConverter is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with TAudioConverter.  If not, see <http://www.gnu.org/licenses/>.
  *
  * }

unit UnitMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, Mask, JvExMask, JvSpin, XPMan, ExtCtrls,
  Menus,
  JvBaseDlg, JvBrowseFolder, JvExStdCtrls, JvToolEdit,
  JvComponentBase,
  JvCreateProcess, JvThread, ComCtrls, JvExComCtrls, ShellAPI,
  StrUtils,
  MediaInfoDll, JvComputerInfoEx, IniFiles, JvDragDrop,
  JvUrlListGrabber, JvUrlGrabbers, CommCtrl, sSkinProvider, sSkinManager,
  sPanel,
  sButton, sLabel, sListBox, sCheckBox, sComboBox, sEdit, sGauge, sBitBtn,
  Vcl.ImgList, acAlphaImageList, JvSearchFiles, Vcl.Samples.Spin, JvBackgrounds,
  JvListView, JvExControls, JvXPCore, JvXPButtons, acPNG, JvProgressBar,
  JvXPProgressBar, JvTrayIcon, UnitEncoder, JvAnimatedImage, JvGIFCtrl,
  JvThreadDialog, JvCpuUsage, TlHelp32, EncdDecd, UnitFileInfo;

type
  TMainForm = class(TForm)
    RemoveBtn: TsBitBtn;
    RemoveAllBtn: TsBitBtn;
    UpBtn: TsBitBtn;
    DownBtn: TsBitBtn;
    OutputBtn: TsBitBtn;
    StartBtn: TsBitBtn;
    StopBtn: TsBitBtn;
    XPManifest1: TXPManifest;
    AddMenu: TPopupMenu;
    AddFiles1: TMenuItem;
    AddFolder1: TMenuItem;
    OpenDialog: TOpenDialog;
    OpenFolderDialog: TJvBrowseForFolderDialog;
    LogsBtn: TsBitBtn;
    PositionTimer: TTimer;
    AddBtn: TsBitBtn;
    SystemInfo: TJvComputerInfoEx;
    FAACBitrateEdit: TJvSpinEdit;
    Label20: TsLabel;
    DragDrop: TJvDragDrop;
    UpdateThread: TJvThread;
    UpdateChecker: TJvHttpUrlGrabber;
    QaacPanel: TsPanel;
    QaacEncodeMethodList: TsComboBox;
    QaacQualityList: TsComboBox;
    QaacBitrateEdit: TJvSpinEdit;
    QaacvQualityEdit: TJvSpinEdit;
    Label34: TsLabel;
    Label35: TsLabel;
    QaacHEBtn: TsCheckBox;
    AftenPanel: TsPanel;
    OggPanel: TsPanel;
    OggencodeList: TsComboBox;
    OggQualityEdit: TJvSpinEdit;
    OggBitrateEdit: TJvSpinEdit;
    OggManagedBitrateBtn: TsCheckBox;
    Label38: TsLabel;
    Label39: TsLabel;
    AftenEncodeList: TsComboBox;
    AftenQualityEdit: TJvSpinEdit;
    AftenBitrateEdit: TJvSpinEdit;
    Label41: TsLabel;
    Label42: TsLabel;
    MainMenu: TMainMenu;
    File1: TMenuItem;
    AddFiles2: TMenuItem;
    AddFolder2: TMenuItem;
    Exit1: TMenuItem;
    Edit1: TMenuItem;
    Up1: TMenuItem;
    Down1: TMenuItem;
    Remove1: TMenuItem;
    RemoveAll1: TMenuItem;
    ools1: TMenuItem;
    LogsOutput1: TMenuItem;
    Info1: TMenuItem;
    Help1: TMenuItem;
    About1: TMenuItem;
    CheckUpdate1: TMenuItem;
    ListMenu: TPopupMenu;
    AddFiles3: TMenuItem;
    AddFolder3: TMenuItem;
    Remove2: TMenuItem;
    Clear1: TMenuItem;
    OpenDirectory1: TMenuItem;
    Info2: TMenuItem;
    SameAsSourceBtn: TsCheckBox;
    AudioEffectsBtn: TsBitBtn;
    ProgressPanel: TsPanel;
    Log2Btn: TsBitBtn;
    PageImages: TsAlphaImageList;
    AudioTrackList: TsComboBox;
    FileSearch: TJvSearchFiles;
    AddFolderTree1: TMenuItem;
    Play1: TMenuItem;
    AddFolderTree2: TMenuItem;
    AudioMethodList: TsComboBox;
    LamePanel: TsPanel;
    LameEncodeList: TsComboBox;
    LameBitrateEdit: TJvSpinEdit;
    LameVBREdit: TJvSpinEdit;
    Label7: TsLabel;
    Label13: TsLabel;
    LameQualityEdit: TJvSpinEdit;
    Label14: TsLabel;
    SummaryView: TTreeView;
    OpenOut2Btn: TsBitBtn;
    WavePanel: TsPanel;
    AddFolderTree3: TMenuItem;
    ProgressImages: TsAlphaImageList;
    ListImage: TsAlphaImageList;
    PostEncodeList: TsComboBox;
    Timer: TTimer;
    FLACPanel: TsPanel;
    FLACCompList: TsComboBox;
    FLACEMSBtn: TsCheckBox;
    TimePassedLabel: TsLabel;
    FHGPanel: TsPanel;
    FHGMethodList: TsComboBox;
    FHGProfileList: TsComboBox;
    FHGQualityEdit: TJvSpinEdit;
    FHGBitrateEdit: TJvSpinEdit;
    Label2: TsLabel;
    Label3: TsLabel;
    TotalProgressBar: TsGauge;
    StatusList: TsAlphaImageList;
    OpusPanel: TsPanel;
    OpusCompEdit: TJvSpinEdit;
    OpusEncodeMethodList: TsComboBox;
    OpusBitrateEdit: TJvSpinEdit;
    Label1: TsLabel;
    Label4: TsLabel;
    TrayIcon: TJvTrayIcon;
    ProgressBar1: TsGauge;
    ProgressBar2: TsGauge;
    ProgressBar3: TsGauge;
    ProgressBar4: TsGauge;
    ProgressBar5: TsGauge;
    ProgressBar6: TsGauge;
    ProgressBar7: TsGauge;
    ProgressBar8: TsGauge;
    sPanel4: TsPanel;
    sSkinManager1: TsSkinManager;
    sSkinProvider1: TsSkinProvider;
    CPUBar: TsGauge;
    MemoryBar: TsGauge;
    MPCPanel: TsPanel;
    MPCQualityBar: TTrackBar;
    sLabel1: TsLabel;
    MPCQualityEdit: TsEdit;
    BitDepthList: TsComboBox;
    ChangeLog1: TMenuItem;
    sLabel2: TsLabel;
    MACPanel: TsPanel;
    MACLevelList: TsComboBox;
    TTAPanel: TsPanel;
    TAKPanel: TsPanel;
    TAKPresetList: TsComboBox;
    EmalBtn: TsBitBtn;
    DirectoryEdit: TsEdit;
    SelectDirBtn: TsButton;
    FAACPanel: TsPanel;
    FileList: TsListBox;
    SettingsPanel: TsPanel;
    SettingsBtn: TsBitBtn;
    LameTagList: TsComboBox;
    sLabel3: TsLabel;
    sLabel4: TsLabel;
    SeeLogtxt1: TMenuItem;
    MainPanel: TsPanel;
    WikiBtn: TsButton;
    sLabel5: TsLabel;
    NeroPanel: TsPanel;
    NeroMethodList: TsComboBox;
    NeroBitrateEdit: TJvSpinEdit;
    NeroQualityEdit: TJvSpinEdit;
    sLabel6: TsLabel;
    sLabel7: TsLabel;
    NeroProfileList: TsComboBox;
    AlacPanel: TsPanel;
    DirecortyLabel: TsLabel;
    DonationBtn: TsBitBtn;
    WMAPanel: TsPanel;
    WMAMethodList: TsComboBox;
    WMACodecList: TsComboBox;
    sLabel8: TsLabel;
    WMAQualityList: TsComboBox;
    WMABitrateEdit: TJvSpinEdit;
    WavPackPanel: TsPanel;
    WavPackMethodList: TsComboBox;
    sLabel9: TsLabel;
    WavPackBitrateEdit: TJvSpinEdit;
    WavPackExtraBtn: TsCheckBox;
    WavPackCorrectionBtn: TsCheckBox;
    AudioCodecBtn: TsBitBtn;
    CodecMenu: TPopupMenu;
    Lossy1: TMenuItem;
    Lossless1: TMenuItem;
    Hybrid1: TMenuItem;
    FAACAAC1: TMenuItem;
    QAACAAC1: TMenuItem;
    FFMpegAC31: TMenuItem;
    OggVorbisOgg1: TMenuItem;
    LameMP31: TMenuItem;
    FhgaacencAAC1: TMenuItem;
    OpusOpus1: TMenuItem;
    MPCEncMPC1: TMenuItem;
    NeroAACEncAAC1: TMenuItem;
    WMAEncodeWMA1: TMenuItem;
    FLACFLAC1: TMenuItem;
    MonkeysAudioAPE1: TMenuItem;
    TAEncTTA1: TMenuItem;
    AKEncTAK1: TMenuItem;
    REFALACALAC1: TMenuItem;
    WavPackVW1: TMenuItem;
    Uncompressed1: TMenuItem;
    FFMpegWAV1: TMenuItem;
    DownloadNeroAACTools1: TMenuItem;
    InfoBtn: TsBitBtn;
    sLabel10: TsLabel;
    sLabel11: TsLabel;
    procedure AddFiles1Click(Sender: TObject);
    procedure AddFolder1Click(Sender: TObject);
    procedure AddBtnClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure StartBtnClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure StopBtnClick(Sender: TObject);
    procedure PositionTimerTimer(Sender: TObject);
    procedure LogsBtnClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure OutputBtnClick(Sender: TObject);
    procedure RemoveBtnClick(Sender: TObject);
    procedure RemoveAllBtnClick(Sender: TObject);
    procedure UpBtnClick(Sender: TObject);
    procedure DownBtnClick(Sender: TObject);
    procedure AboutBtnClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure DragDropDrop(Sender: TObject; Pos: TPoint; Value: TStrings);
    procedure InfoBtnClick(Sender: TObject);
    procedure UpdateThreadExecute(Sender: TObject; Params: Pointer);
    procedure UpdateCheckerDoneFile(Sender: TObject; FileName: string;
      FileSize: Integer; Url: string);
    procedure QaacHEBtnClick(Sender: TObject);
    procedure QaacEncodeMethodListChange(Sender: TObject);
    procedure OggencodeListChange(Sender: TObject);
    procedure AftenEncodeListChange(Sender: TObject);

    procedure UpdateListboxScrollBox(ListBox: TsListBox);

    // check if string is numeric
    function IsStringNumeric(Str: string): Boolean;
    procedure UpdateBtnClick(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure OpenDirectory1Click(Sender: TObject);
    procedure MplayerProcessTerminate(Sender: TObject; ExitCode: Cardinal);
    procedure AudioEffectsBtnClick(Sender: TObject);
    procedure FileListDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure FileListClick(Sender: TObject);
    procedure AudioTrackListChange(Sender: TObject);
    procedure AddFolderTree1Click(Sender: TObject);
    procedure FileSearchProgress(Sender: TObject);
    procedure FileSearchFindFile(Sender: TObject; const AName: string);
    procedure Play1Click(Sender: TObject);
    procedure AudioMethodListChange(Sender: TObject);
    procedure LameEncodeListChange(Sender: TObject);
    procedure FileListAdvancedCustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
      var DefaultDraw: Boolean);
    procedure TimerTimer(Sender: TObject);
    procedure AudioEncoderListChange(Sender: TObject);
    procedure sBitBtn1Click(Sender: TObject);
    procedure Force32bitBtnClick(Sender: TObject);
    procedure SameAsSourceBtnClick(Sender: TObject);
    procedure FHGMethodListChange(Sender: TObject);
    procedure TrayIconBalloonClick(Sender: TObject);
    procedure TrayIconClick(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure TrayIconDblClick(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FileListKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure MPCQualityBarChange(Sender: TObject);
    procedure ChangeLog1Click(Sender: TObject);
    procedure PostEncodeListChange(Sender: TObject);
    procedure sLabel2Click(Sender: TObject);
    procedure EmalBtnClick(Sender: TObject);
    procedure SelectDirBtnClick(Sender: TObject);
    procedure SettingsBtnClick(Sender: TObject);
    procedure sLabel3Click(Sender: TObject);
    procedure SeeLogtxt1Click(Sender: TObject);
    procedure WikiBtnClick(Sender: TObject);
    procedure NeroMethodListChange(Sender: TObject);
    procedure DonationBtnClick(Sender: TObject);
    procedure WMAMethodListChange(Sender: TObject);
    procedure WavPackMethodListChange(Sender: TObject);
    procedure AudioCodecBtnClick(Sender: TObject);
    procedure FAACAAC1Click(Sender: TObject);
    procedure QAACAAC1Click(Sender: TObject);
    procedure FFMpegAC31Click(Sender: TObject);
    procedure OggVorbisOgg1Click(Sender: TObject);
    procedure LameMP31Click(Sender: TObject);
    procedure FhgaacencAAC1Click(Sender: TObject);
    procedure OpusOpus1Click(Sender: TObject);
    procedure MPCEncMPC1Click(Sender: TObject);
    procedure NeroAACEncAAC1Click(Sender: TObject);
    procedure WMAEncodeWMA1Click(Sender: TObject);
    procedure FLACFLAC1Click(Sender: TObject);
    procedure MonkeysAudioAPE1Click(Sender: TObject);
    procedure TAEncTTA1Click(Sender: TObject);
    procedure AKEncTAK1Click(Sender: TObject);
    procedure REFALACALAC1Click(Sender: TObject);
    procedure WavPackVW1Click(Sender: TObject);
    procedure FFMpegWAV1Click(Sender: TObject);
    procedure DownloadNeroAACTools1Click(Sender: TObject);
  private
    { Private declarations }
    // CommandLines1: TStringList;
    { 1=x264, 2=ffmpeg, 3=mkv, 4=mp4box, 5=mkvextract, 7=neroaac, 8=qaac,
      9=mp4box_extract, 10=oggenc, 11=aften, 12=mkvextract-chapter, 13=mp4box-chapter,
      14=ffmpeg-encoding, 15=sox, 16=lame, 17=flac, 18=fhg, 19=opus, 20=mpc, 21=ape,
      22=tta, 23=tak, 24=nerotag, 25=ALAC, 27=lyric downloader, 28=wavpack }
    SubtitleFiles: TStringList;
    AudioIndexes: TStringList;
    AudioTracks: TStringList;
    CurrentFileIndexes: TStringList;
    Files: TStringList;
    FilesToCheck: TStringList;
    Durations: TStringList;
    ExtensionsForCopy: TStringList;
    CopyExtension: TStringList;

    FFMpegPath, QaacPath, OggEncPath, SoxPath, LamePath, FLACPath: string;
    FHGPath, OpusPath: string;
    MPCPath: string;
    MACPath: string;
    TTAPath: string;
    TAKPath: string;
    NeroEncPath: string;
    NeroTagPath: string;
    RefAlacPath: string;
    WmaEncodePath: string;
    LyricDownloader: string;
    WavPackPath: string;

    TotalLength: Int64;

    FileIndex: Integer;
    DurationIndex: Integer;
    StoppedByUser: Boolean;
    LastPercent: Integer;

    LastDirectory: string;

    TimePassed: Int64;

    Encoder1: TEncoder;
    Encoder2: TEncoder;
    Encoder3: TEncoder;
    Encoder4: TEncoder;
    Encoder5: TEncoder;
    Encoder6: TEncoder;
    Encoder7: TEncoder;
    Encoder8: TEncoder;

    CpuUsage: TJvCpuUsage;
    TotalCMDCount: integer;
    AudioEncoderIndex: integer;

    // returns % done
    function x264Percentage(const x264Output: string): Integer;
    function FFMpegPercentage(const FFMpegOutput: string;
      const DurationStr: string): Integer;
    function MkvExtractPercentage(const MkvExtractOutput: string): Integer;
    function FAACPercentage(const FAACOutput: string): Integer;
    function SoXPercentage(const SoxOutput: string): Integer;
    function LamePercentage(const LameOutput: string): Integer;
    function FLACPercentage(const FLACOutput: string): Integer;
    function OpusPercentage(const OpusOutput: string;
      const DurationStr: string): integer;
    function MPCPercentage(const MPCOutput: string): integer;
    function ApePercentage(const APEOutput: string): integer;
    function TAKPercentage(const TAKOutput: string): integer;
    function NeroPercentage(const NeroOutput: string;
      const DurationStr: string): integer;
    function WMAEncoderPercentage(const WMAOutput: string): integer;

    function GetPercentage(const EncoderIndex: integer): integer;
    function UpdateProgressUI(): integer;
    procedure LaunchProcesses(const ProcessCount: integer);

    function SubStringOccurences(const subString, sourceString: string)
      : integer;

    // get full info for selected file
    procedure GetFullInfo(const FileName: string);

    // hh:mm:ss to int
    function TimeToInt(const TimeStr: string): Integer;

    // gets duration of a file in seconds
    // FrameCount
    function GetDuration(Index: integer): string;
    function GetDurationEx(const FileName: string): integer;
    // deletes temp. files
    procedure DeleteTempFiles;

    // gets artwork as base64
    function GetArtwork(const FileName: string): string;
    // saves artwork to dest. folder
    procedure SaveArtwork(const ArtworkData: ansistring;
      const OutputFolder: string; const FileName: string);
    procedure SaveExternalArtwork(const FileDir: string;
      const OutputFolder: string);
    function SaveArtwork2(const ArtworkData: ansistring;
      const OutputFolder: string; const FileName: string): string;

    // checks output files to detect errors
    function CheckOutputFiles: Boolean;

    // checks a single output file
    // function CheckOutputFile(const FileIndex: integer): Boolean;

    // disable/enable UI
    procedure DisableUI();
    procedure EnableUI();

    // sets panel visible
    procedure SetPanelState(const EncoderIndex: integer);

    // adds command line for x264.exe
    procedure AddCommandLine(Index: Integer; AdvancedOptions: string;
      const EncoderIndex: integer);

    // fills summary list
    procedure FillSummaryList();
    procedure FillProgressList();

    // shuts down, logs off or reboots
    function ShutDown(RebootParam: Longword): Boolean;

    // gets audio codec
    function CodecToExtension(const AudioCodec: string): string;

    function IntToTime(IntTime: Integer): string;

    // save/load options
    procedure LoadOptions();
    procedure SaveOptions();

    // adds a file to the file list extracting audio info
    procedure AddFile(const FileName: string; const AddingLater: Boolean);

    // checks if os is 64-bit
    function IsOS64Bit: Boolean;
    procedure Set32_64Backend();

    // tags
    function CreateTagCMD(const FileName: string): string;

    function GetFileFolderName(const FileName: string): string;

    procedure SaveLogs();
    procedure DeleteLogs();

    // removes '"' from tags
    function RemoveQuotation(const Source: string): string;

    // checks if source is audio only
    function IsAudioOnly(const FileName: string): Boolean;

    // creates cmd for ffmpeg according to bit depth
    function CreateBitDepthCMD(const FileName: string): string;

    procedure Log(const MSG: string);

    // removes non-digit chars
    function RemoveNonDigits(const InputStr: string): string;

    // creates command line for embeding artwork
    function CreateArtworkCMD(const FileName: string): string;

    // converts binary to base64
    function FileToBase64(const FileName: string): ansistring;

    // writes given message to specified log
    procedure AddToLog(const LogID: ShortInt; const MSG: string);

    // writes given line to given file
    procedure WriteLnToFile(const FileName: string; const Line: string);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMCopyData(var Message: TWMCopyData); message WM_COPYDATA;
  public
    { Public declarations }
    AppFolder: string;
    AppData: string;
    MyDoc: string;
    AddingStopped: Boolean;
    // decides best number of processes
    function DecideNumOfProcesses(): integer;

    // gets temp directory
    function GetTempDirectory: string;
  end;

const
  BuildInt = 1191;

const
  SWindowClassName = 'TAudioConverterUniqueName';
  Portable = False;

var
  MainForm: TMainForm;

implementation

uses UnitLog, windows7taskbar, UnitInfo, UnitAbout,
  UnitUpdater, UnitSox, UnitProgress, UnitSettings;

{$R *.dfm}

procedure TMainForm.AboutBtnClick(Sender: TObject);
begin

  Self.Enabled := False;
  AboutForm.show;

end;

procedure TMainForm.AddBtnClick(Sender: TObject);
begin

  AddMenu.Popup(AddBtn.Left + Self.Left + 7, Self.Top + AddBtn.Top +
    Round(AddBtn.Height * 2.7))

end;

procedure TMainForm.AddCommandLine(Index: Integer; AdvancedOptions: string;
  const EncoderIndex: integer);
var
  OutAudioFile: string;
  TmpAudioFileName: string;
  FileName: string;
  AudioStr: string;
  // i, j: Integer;
  FileIndex: integer;
  Encoder: TEncoder;
  DepthStr: string;
  StreamIndexCMD: string;
  CopyExt: string;
  FileDuration: string;
  OutputExt: string;
  TmpLst: TStringList;
  Encoding: TEncoding;
begin

  // decide which process to use
  case EncoderIndex of
    1:
      Encoder := Encoder1;
    2:
      Encoder := Encoder2;
    3:
      Encoder := Encoder3;
    4:
      Encoder := Encoder4;
    5:
      Encoder := Encoder5;
    6:
      Encoder := Encoder6;
    7:
      Encoder := Encoder7;
    8:
      Encoder := Encoder8;
  end;

  // paths and files
  FileName := Files[Index];

  TmpAudioFileName := FileName;

  // dest audio extension
  case AudioEncoderIndex of
    0:
      begin
        if (SettingsForm.AACExtList.ItemIndex = 0) and
          (SettingsForm.AACExtList.ItemIndex = 3) then
        begin
          OutputExt := '.' + LowerCase(SettingsForm.AACExtList.Text);
        end
        else
        begin
          OutputExt := '.m4a';
        end;
      end;
    1:
      begin
        OutputExt := '.' + LowerCase(SettingsForm.AACExtList.Text);
      end;
    2:
      begin
        OutputExt := '.ac3';
      end;
    3:
      begin
        OutputExt := '.ogg';
      end;
    4:
      begin
        OutputExt := '.mp3';;
      end;
    5:
      begin
        OutputExt := '.wav';
        TmpAudioFileName := OutAudioFile;
      end;
    6:
      begin
        OutputExt := '.flac';
      end;
    7:
      begin
        OutputExt := '.' + LowerCase(SettingsForm.AACExtList.Text);
      end;
    8:
      begin
        OutputExt := '.opus';
      end;
    9:
      begin
        OutputExt := '.mpc';
      end;
    10:
      begin
        OutputExt := '.ape';
      end;
    11:
      begin
        OutputExt := '.tta';
      end;
    12:
      begin
        OutputExt := '.tak';
      end;
    13:
      begin
        OutputExt := '.' + LowerCase(SettingsForm.AACExtList.Text);
      end;
    14:
      begin
        OutputExt := '.' + LowerCase(SettingsForm.AACExtList.Text);
      end;
    15:
      begin
        OutputExt := '.wma';
      end;
    16:
      begin
        OutputExt := '.wv';
      end;
  end;

  // generate output file path
  // same as source
  if not SameAsSourceBtn.Checked then
  begin
    TmpAudioFileName := ExcludeTrailingPathDelimiter(DirectoryEdit.Text) + '\' +
      GetFileFolderName(FileName) + '\' + ExtractFileName(FileName);
    OutAudioFile := ChangeFileExt(TmpAudioFileName, OutputExt);
  end
  else
  begin
    OutAudioFile := ChangeFileExt(FileName, OutputExt);
  end;

  FileIndex := 0;
  if FileExists(OutAudioFile) then
  begin
    while FileExists(OutAudioFile) do
    begin
      Inc(FileIndex);
      OutAudioFile := ChangeFileExt(TmpAudioFileName,
        '_' + FloatToStr(FileIndex) + OutputExt);
    end;
  end;

  // create dest folder
  if not SameAsSourceBtn.Checked then
  begin
    if not DirectoryExists(ExtractFileDir(OutAudioFile)) then
    begin
      if not ForceDirectories(ExtractFileDir(OutAudioFile)) then
      begin
        AddToLog(0, 'Could not create folder: ' + ExtractFileDir(OutAudioFile));
      end;
    end;
  end;

  // create artwork in output folder
  if SettingsForm.ArtworkBtn.Checked then
  begin
    // copy artwork to output folder
    if SettingsForm.ArtworkList.ItemIndex = 0 then
    begin
      SaveArtwork(GetArtwork(FileName), ExtractFileDir(OutAudioFile),
        ChangeFileExt(ExtractFileName(OutAudioFile), ''));

      // copy external artowk
      if SettingsForm.Artwork2Btn.Checked then
      begin
        SaveExternalArtwork(ExtractFileDir(FileName),
          ExtractFileDir(OutAudioFile));
      end;
    end;
  end;

  // get duration of file
  FileDuration := Durations[Index];

  // audio encoding
  case AudioMethodList.ItemIndex of
    0: // encode audio
      begin

        // avs files no audio encoding
        if AudioIndexes[Index] <> '-1' then
        begin

          // bit depth
          case BitDepthList.ItemIndex of
            0:
              DepthStr := CreateBitDepthCMD(FileName);
            1:
              DepthStr := '-acodec pcm_s16le';
            2:
              DepthStr := '-acodec pcm_s24le';
            3:
              DepthStr := '-acodec pcm_s32le';
          end;

          // stream index
          if IsAudioOnly(FileName) then
          begin
            StreamIndexCMD := ' ';
          end
          else
          begin
            StreamIndexCMD := '-map 0:' + AudioIndexes[Index] + ' ';
          end;

          // audio decoding
          AudioStr := ' -y -i "' + FileName + '" -threads 0 -vn ' + DepthStr +
            ' -f wav ' + StreamIndexCMD;

          // audio channels carried here because sox caused problems
          if SoXForm.EnableBtn.Checked then
          begin
            case SoXForm.ChannelList.ItemIndex of
              1:
                AudioStr := AudioStr + ' -ac 1';
              2:
                AudioStr := AudioStr + ' -ac 2';
              3:
                AudioStr := AudioStr + ' -ac 6';
            end;

            // sample rate
            if SoXForm.SampleList.ItemIndex > 0 then
            begin
              AudioStr := AudioStr + ' -af aresample=resampler=soxr -ar ' +
                SoXForm.SampleList.Text;
            end;

          end;

          if AudioEncoderIndex <> 5 then
          begin
            TmpAudioFileName := ChangeFileExt(FileName, '.wav');
            TmpAudioFileName := ExcludeTrailingPathDelimiter
              (SettingsForm.TempEdit.Text) + '\' +
              ExtractFileName(TmpAudioFileName);
          end
          else
          begin
            TmpAudioFileName := OutAudioFile;
          end;
          AudioStr := AudioStr + ' "' + TmpAudioFileName + '"';
          Encoder.CommandLines.Add(AudioStr);
          Encoder.Paths.Add(FFMpegPath);
          Encoder.FileNames.Add(FileName);
          CurrentFileIndexes.Add(FloatToStr(Index));
          Encoder.Durations.Add(FileDuration);
          Encoder.Infos.Add('Decoding audio');

          Encoder.ProcessTypes.Add('2');

          // in order to show speed
          TotalLength := TotalLength + StrToInt(FileDuration);

          // audio filters
          AudioStr := '';

          with SoXForm do
          begin

            if EnableBtn.Checked then
            begin

              // normalize
              if NormBtn.Checked then
              begin
                AudioStr := AudioStr + ' --norm ';
              end;

              // volume
              if VolumeBtn.Checked then
              begin
                AudioStr := AudioStr + ' −−vol ' + ReplaceText(VolumeEdit.Text,
                  ',', '.');
              end;

              // thread mode
              if SoXForm.ThreadBtn.Checked then
              begin
                AudioStr := AudioStr + ' −−multi-threaded ';
              end;

              // clipping guard
              if GuardBtn.Checked then
              begin
                AudioStr := AudioStr + ' -G ';
              end;

              if AudioStr <> '' then
              begin
                AudioStr := AudioStr + ' "' + TmpAudioFileName + '"';
                TmpAudioFileName := SettingsForm.TempEdit.Text + '\sox_' +
                  FloatToStr(Index) + '.wav';
                AudioStr := AudioStr + ' -V6 --show-progress "' +
                  TmpAudioFileName + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(SoxPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));
                Encoder.Infos.Add('Applying effects to audio');

                Encoder.ProcessTypes.Add('15');
              end;

            end;
          end;

          // audio encoding
          AudioStr := '';

          case AudioEncoderIndex of
            0: // ffmpeg aac
              begin

                // encoding mode
                AudioStr := AudioStr + ' -b:a ' + FAACBitrateEdit.Text + '000';

                // last cmd
                AudioStr := ' -y -i "' +
                  TmpAudioFileName + '" "' + OutAudioFile + '" ' + AudioStr;

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(FFMpegPath);
                Encoder.FileNames.Add(FileName);
                Encoder.Durations.Add(FileDuration);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('2');

                // nero tag
                if SettingsForm.TagsBtn.Checked and FileExists(NeroTagPath) then
                begin
                  AudioStr := '';
                  AudioStr := ' "' + OutAudioFile + '" ' +
                    CreateTagCMD(FileName);

                  Encoder.CommandLines.Add(AudioStr);
                  Encoder.Paths.Add(NeroTagPath);
                  Encoder.FileNames.Add(FileName);
                  // Encoder.Durations.Add(FileDuration);
                  CurrentFileIndexes.Add(FloatToStr(Index));

                  Encoder.Infos.Add('Writing Tags');

                  Encoder.ProcessTypes.Add('24');
                end;
              end;
            1: // qaac
              begin
                // encoding mode
                case QaacEncodeMethodList.ItemIndex of
                  0: // abr
                    begin
                      AudioStr := AudioStr + ' --abr ' + QaacBitrateEdit.Text;
                    end;
                  1: // tvbr
                    begin
                      AudioStr := AudioStr + ' --tvbr ' + QaacvQualityEdit.Text;
                    end;
                  2: // cvbr
                    begin
                      AudioStr := AudioStr + ' --cvbr ' + QaacBitrateEdit.Text;
                    end;
                  3: // cbr
                    begin
                      AudioStr := AudioStr + ' --cbr ' + QaacBitrateEdit.Text;
                    end;
                end;

                // profile
                if QaacHEBtn.Checked then
                begin
                  AudioStr := AudioStr + ' --he';
                end;

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) +
                  ' --threading --rate keep "' + TmpAudioFileName + '" -o "' +
                  OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(QaacPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('8');
              end;
            2: // ac3
              begin
                // encoding mode
                case AftenEncodeList.ItemIndex of
                  0: // quality
                    begin
                      AudioStr := AudioStr + ' -q:a ' + AftenQualityEdit.Text;
                    end;
                  1: // cbr
                    begin
                      AudioStr := AudioStr + ' -b:a ' +
                        AftenBitrateEdit.Text + '000';
                    end;
                end;

                // last cmd
                AudioStr := ' -y -i "' + TmpAudioFileName + '" ' + AudioStr +
                  ' -acodec ac3 "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(FFMpegPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));
                Encoder.Durations.Add(FileDuration);

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('2');
              end;
            3: // oggenc
              begin
                // encoding mode
                case OggencodeList.ItemIndex of
                  0: // quality
                    begin
                      AudioStr := AudioStr + ' -q ' + OggQualityEdit.Text;
                    end;
                  1: // bitrate
                    begin
                      AudioStr := AudioStr + ' -b ' + OggBitrateEdit.Text;

                      // managed bitrate mode
                      if OggManagedBitrateBtn.Checked then
                      begin
                        AudioStr := AudioStr + ' --managed ';
                      end;

                    end;
                end;

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) + '  "' +
                  TmpAudioFileName + '" -o "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(OggEncPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('10');
              end;
            4: // lame
              begin

                case LameEncodeList.ItemIndex of
                  0: // cbr
                    begin
                      AudioStr := AudioStr + ' --cbr -b ' +
                        LameBitrateEdit.Text;
                    end;
                  1: // abr
                    begin
                      AudioStr := AudioStr + ' --abr ' + LameBitrateEdit.Text;
                    end;
                  2: // vbr
                    begin
                      AudioStr := AudioStr + ' -V ' +
                        ReplaceStr(LameVBREdit.Text, ',', '.');
                    end;
                end;

                AudioStr := AudioStr + CreateTagCMD(FileName) +
                  ' --verbose  -q ' + LameQualityEdit.Text;

                // tags
                case LameTagList.ItemIndex of
                  1:
                    AudioStr := AudioStr + ' --id3v1-only ';
                  2:
                    AudioStr := AudioStr + ' --id3v2-only ';
                end;

                // last cmd
                AudioStr := AudioStr + '  "' + TmpAudioFileName + '" -o "' +
                  OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(LamePath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('16');

              end;
            5: // wav
              begin

              end;
            6: // flac
              begin

                AudioStr := AudioStr + ' -' +
                  FloatToStr(FLACCompList.ItemIndex);

                if FLACEMSBtn.Checked then
                begin
                  AudioStr := AudioStr + ' -e ';
                end;

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) + '  "' +
                  TmpAudioFileName + '" -o "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(FLACPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('17');
              end;
            7: // FHG
              begin

                // encoding mode
                case FHGMethodList.ItemIndex of
                  0: // cbr
                    begin
                      AudioStr := AudioStr + ' --cbr ' + FHGBitrateEdit.Text;

                      // profile
                      case FHGProfileList.ItemIndex of
                        0:
                          AudioStr := AudioStr + ' --profile auto';
                        1:
                          AudioStr := AudioStr + ' --profile lc';
                        2:
                          AudioStr := AudioStr + ' --profile he';
                        3:
                          AudioStr := AudioStr + ' --profile hev2';
                      end;
                    end;
                  1: // vbr
                    begin
                      AudioStr := AudioStr + ' --vbr ' + FHGQualityEdit.Text;
                    end;
                end;

                // last cmd
                AudioStr := AudioStr + ' "' + TmpAudioFileName + '" "' +
                  OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(FHGPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('18');

                // nero tag
                if SettingsForm.TagsBtn.Checked and FileExists(NeroTagPath) then
                begin
                  AudioStr := '';
                  AudioStr := ' "' + OutAudioFile + '" ' +
                    CreateTagCMD(FileName);

                  Encoder.CommandLines.Add(AudioStr);
                  Encoder.Paths.Add(NeroTagPath);
                  Encoder.FileNames.Add(FileName);
                  // Encoder.Durations.Add(FileDuration);
                  CurrentFileIndexes.Add(FloatToStr(Index));

                  Encoder.Infos.Add('Writing Tags');

                  Encoder.ProcessTypes.Add('24');
                end;

              end;
            8: // opus
              begin

                // encoding mode
                case OpusEncodeMethodList.ItemIndex of
                  0: // vbr
                    begin
                      AudioStr := AudioStr + ' --vbr ';
                    end;
                  1: // cvbr
                    begin
                      AudioStr := AudioStr + ' --cvbr ';
                    end;
                  2: // cbr
                    begin
                      AudioStr := AudioStr + ' --hard-cbr ';
                    end;
                end;

                AudioStr := AudioStr + ' --comp ' + OpusCompEdit.Text;
                AudioStr := AudioStr + ' --bitrate ' + OpusBitrateEdit.Text;

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) + ' "' +
                  TmpAudioFileName + '" "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(OpusPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));
                Encoder.Durations.Add(FileDuration);

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('19');

              end;
            9: // mpc
              begin

                AudioStr := AudioStr + ' --quality ' + MPCQualityEdit.Text +
                  ' --unicode ';

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) + ' "' +
                  TmpAudioFileName + '" "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(MPCPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('20');
              end;
            10: // ape
              begin

                case MACLevelList.ItemIndex of
                  0:
                    AudioStr := AudioStr + ' -c1000';
                  1:
                    AudioStr := AudioStr + ' -c2000';
                  2:
                    AudioStr := AudioStr + ' -c3000';
                  3:
                    AudioStr := AudioStr + ' -c4000';
                  4:
                    AudioStr := AudioStr + ' -c5000';
                end;

                // last cmd
                AudioStr := CreateTagCMD(FileName) + ' "' + TmpAudioFileName +
                  '" "' + OutAudioFile + '" ' + AudioStr;

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(MACPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('21');
              end;
            11: // tta
              begin

                // last cmd
                AudioStr := CreateTagCMD(FileName) + ' -e "' + TmpAudioFileName
                  + '" -o "' + OutAudioFile + '" ';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(TTAPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('22');
              end;
            12: // tak
              begin

                // last cmd
                AudioStr := ' -overwrite -e -p' +
                  FloatToStr(TAKPresetList.ItemIndex + 1) + ' ' +
                  CreateTagCMD(FileName) + ' "' + TmpAudioFileName + '" "' +
                  OutAudioFile + '" ';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(TAKPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('23');
              end;
            13: // neroaac
              begin

                // encoding mode
                case NeroMethodList.ItemIndex of
                  0: // quality
                    begin
                      AudioStr := AudioStr + ' -q ' +
                        ReplaceStr(NeroQualityEdit.Text, ',', '.');
                    end;
                  1: // abr
                    begin
                      AudioStr := AudioStr + ' -br ' +
                        NeroBitrateEdit.Text + '000';
                    end;
                  2: // cbr
                    begin
                      AudioStr := AudioStr + ' -cbr ' +
                        NeroBitrateEdit.Text + '000';
                    end;
                end;

                // profile
                case NeroProfileList.ItemIndex of
                  1:
                    AudioStr := AudioStr + ' -lc';
                  2:
                    AudioStr := AudioStr + ' -he';
                  3:
                    AudioStr := AudioStr + ' -hev2';
                end;

                // last cmd
                AudioStr := AudioStr + ' -if "' + TmpAudioFileName + '" -of "' +
                  OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(NeroEncPath);
                Encoder.FileNames.Add(FileName);
                Encoder.Durations.Add(FileDuration);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('7');

                // nero tag
                if SettingsForm.TagsBtn.Checked then
                begin
                  AudioStr := '';
                  AudioStr := ' "' + OutAudioFile + '" ' +
                    CreateTagCMD(FileName);

                  Encoder.CommandLines.Add(AudioStr);
                  Encoder.Paths.Add(NeroTagPath);
                  Encoder.FileNames.Add(FileName);
                  // Encoder.Durations.Add(FileDuration);
                  CurrentFileIndexes.Add(FloatToStr(Index));

                  Encoder.Infos.Add('Writing Tags');

                  Encoder.ProcessTypes.Add('24');
                end;

              end;
            14: // alac
              begin

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) +
                  ' --threading --rate keep "' + TmpAudioFileName + '" -o "' +
                  OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(RefAlacPath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('25');
              end;
            15: // wmaencoder
              begin
                case WMAMethodList.ItemIndex of
                  0:
                    begin
                      AudioStr := AudioStr + ' --quality ' +
                        WMAQualityList.Text;
                    end;
                  1:
                    begin
                      AudioStr := AudioStr + ' --bitrate ' + WMABitrateEdit.Text
                    end;
                end;

                case WMACodecList.ItemIndex of
                  0:
                    AudioStr := AudioStr + ' --codec std ';
                  1:
                    AudioStr := AudioStr + ' --codec pro ';
                  2:
                    AudioStr := AudioStr + ' --codec lsl ';
                  3:
                    AudioStr := AudioStr + ' --codec voice ';
                end;

                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) + ' "' +
                  TmpAudioFileName + '" "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(WmaEncodePath);
                Encoder.FileNames.Add(FileName);
                CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('26');
              end;
            16: // wavpack
              begin
                case WavPackMethodList.ItemIndex of
                  0:
                    begin
                      AudioStr := AudioStr + ' ';
                    end;
                  1:
                    begin
                      AudioStr := AudioStr + ' -b' + WavPackBitrateEdit.Text;

                      if WavPackCorrectionBtn.Checked then
                      begin
                        AudioStr := AudioStr + ' -c '
                      end;
                    end;
                end;

                AudioStr := AudioStr + ' -h ';
                if WavPackExtraBtn.Checked then
                begin
                  AudioStr := AudioStr + ' -x '
                end;
                // last cmd
                AudioStr := AudioStr + CreateTagCMD(FileName) + ' "' +
                  TmpAudioFileName + '" "' + OutAudioFile + '"';

                Encoder.CommandLines.Add(AudioStr);
                Encoder.Paths.Add(WavPackPath);
                Encoder.FileNames.Add(FileName);
                // CurrentFileIndexes.Add(FloatToStr(Index));

                Encoder.Infos.Add('Encoding audio');

                Encoder.ProcessTypes.Add('28');
              end;
          end;

        end;

      end;
    1: // copy audio
      begin
        CopyExt := CodecToExtension(CopyExtension[Index]);
        // in order to show speed
        TotalLength := TotalLength + StrToInt(FileDuration);
        if not SameAsSourceBtn.Checked then
        begin
          TmpAudioFileName := DirectoryEdit.Text + '\' +
            GetFileFolderName(FileName) + '\' +
            ExtractFileName(TmpAudioFileName);
        end;

        OutAudioFile := ChangeFileExt(TmpAudioFileName, CopyExt);

        FileIndex := 0;
        if FileExists(OutAudioFile) then
        begin
          while FileExists(OutAudioFile) do
          begin
            Inc(FileIndex);
            OutAudioFile := ChangeFileExt(TmpAudioFileName,
              '_' + FloatToStr(FileIndex) + CopyExt);

          end;
        end;
        if AudioIndexes[Index] <> '-1' then
        begin
          if CopyExt = '.wav' then
          begin
            AudioStr := ' -y -i "' + FileName + '" -vn -acodec copy -map 0:' +
              AudioIndexes[Index] + ' ' + CreateBitDepthCMD(FileName);
          end
          else
          begin
            AudioStr := ' -y -i "' + FileName + '" -vn -acodec copy -map 0:' +
              AudioIndexes[Index] + ' ';
          end;

          TmpAudioFileName := ChangeFileExt(FileName,
            CodecToExtension(CopyExtension[index]));
          if SameAsSourceBtn.Checked then
          begin
            TmpAudioFileName := ExtractFileDir(FileName) + '\' +
              ExtractFileName(TmpAudioFileName);
          end
          else
          begin
            TmpAudioFileName := DirectoryEdit.Text + '\' +
              GetFileFolderName(FileName) + '\' +
              ExtractFileName(TmpAudioFileName);
          end;
          AudioStr := AudioStr + ' "' + TmpAudioFileName + '"';
          Encoder.CommandLines.Add(AudioStr);
          Encoder.Paths.Add(FFMpegPath);
          Encoder.FileNames.Add(FileName);
          CurrentFileIndexes.Add(FloatToStr(Index));
          Encoder.Durations.Add(FileDuration);
          Encoder.Infos.Add('Copying audio');
          OutAudioFile := TmpAudioFileName;

          Encoder.ProcessTypes.Add('2');
        end;
      end;
  end;

  // download lyric
  if SettingsForm.LyricBtn.Checked then
  begin
    TmpLst := TStringList.Create;
    try
      TmpLst.Add('"' + LyricDownloader + '" "' + FileName + '" "' +
        ChangeFileExt(OutAudioFile, '.lrc') + '"');
    finally
      TmpLst.SaveToFile(SettingsForm.TempEdit.Text + '\' + FloatToStr(Index)
        + '.bat');
      TmpLst.Free;
    end;
    Encoder.CommandLines.Add('');
    Encoder.Paths.Add(SettingsForm.TempEdit.Text + '\' + FloatToStr(Index)
      + '.bat');
    Encoder.FileNames.Add(FileName);
    CurrentFileIndexes.Add(FloatToStr(Index));
    Encoder.Infos.Add('Downloading lyric');

    Encoder.ProcessTypes.Add('27');
  end;

  FilesToCheck.Add(OutAudioFile);

end;

procedure TMainForm.AddFile(const FileName: string; const AddingLater: Boolean);
var
  MediaInfoHandle: Cardinal;
  VDuration: string;
  ABitrate: string;
  ASampleRate: string;
  AChannels: string;
  ACodec: string;
  ALang: string;
  AudioCount: string;
  VideoCount: string;
  AudioID: string;
  i: Integer;
  NewItemStr: string;
  VideoID: string;
  ADuration: string;
  BitDepth: string;
  FileDuration: integer;
  FileSize: string;
  FileInfo: TFileInfo;
  FAudioIndexes: TStringList;
  ExtensionLine: string;
begin

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      FileInfo := TFileInfo.Create(FileName, FFMpegPath);
      FAudioIndexes := TStringList.Create;
      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '1');

        // get length
        VDuration := MediaInfo_Get(MediaInfoHandle, Stream_Video, 0, 'Duration',
          Info_Text, Info_Name);

        // get file size
        FileSize := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'FileSize/String', Info_Text, Info_Name);

        if Length(Trim(VDuration)) < 1 then
        begin
          VDuration := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
            'Duration', Info_Text, Info_Name);
        end;

        FileDuration := GetDurationEx(FileName);
        Durations.Add(FloatToStr(FileDuration));
        // get number of audio tracks
        AudioCount := MediaInfo_Get(MediaInfoHandle, Stream_Audio, 0,
          'StreamCount', Info_Text, Info_Name);

        if not IsStringNumeric(AudioCount) then
        begin
          AudioCount := '0';
        end;

        // if duration is valid
        if (LowerCase(ExtractFileExt(FileName)) <> '.avs') then
        begin

          if IsStringNumeric(VDuration) then
          begin

            VideoCount := MediaInfo_Get(MediaInfoHandle, Stream_Video, 0,
              'StreamCount', Info_Text, Info_Name);

            if not IsStringNumeric(VideoCount) then
            begin
              VideoCount := '0';
            end;

            if IsStringNumeric(VideoCount) or IsStringNumeric(AudioCount) then
            begin

              if (StrToInt(AudioCount) > 0) then
              begin

                VideoID := MediaInfo_Get(MediaInfoHandle, Stream_Video, 0, 'ID',
                  Info_Text, Info_Name);

                if StrToInt(AudioCount) > 0 then
                begin

                  // get id using ffmpeg
                  if not IsAudioOnly(FileName) then
                  begin
                    FileInfo.Start;
                    while FileInfo.FileInfoStatus = fsReading do
                    begin
                      Application.ProcessMessages;
                      Sleep(10);
                    end;
                    FAudioIndexes.AddStrings(FileInfo.AudioStreamIndexes);
                  end
                  else
                  begin
                    FAudioIndexes.Add('0');
                  end;

                  if FAudioIndexes.Count = StrToInt(AudioCount) then
                  begin

                    // fill audio track list
                    for i := 0 to StrToInt(AudioCount) - 1 do
                    begin
                      Application.ProcessMessages;

                      // get info
                      ABitrate := MediaInfo_Get(MediaInfoHandle, Stream_Audio,
                        i, 'BitRate/String', Info_Text, Info_Name);

                      ACodec := MediaInfo_Get(MediaInfoHandle, Stream_Audio, i,
                        'Codec/String', Info_Text, Info_Name);

                      AChannels := MediaInfo_Get(MediaInfoHandle, Stream_Audio,
                        i, 'Channel(s)/String', Info_Text, Info_Name);

                      ASampleRate := MediaInfo_Get(MediaInfoHandle,
                        Stream_Audio, i, 'SamplingRate/String', Info_Text,
                        Info_Name);

                      ALang := MediaInfo_Get(MediaInfoHandle, Stream_Audio, i,
                        'Language/String3', Info_Text, Info_Name);

                      ADuration := MediaInfo_Get(MediaInfoHandle, Stream_Audio,
                        i, 'Duration', Info_Text, Info_Name);
                      BitDepth :=
                        Trim(MediaInfo_Get(MediaInfoHandle, Stream_Audio, 0,
                        'BitDepth', Info_Text, Info_Name));

                      if Length(ABitrate) < 1 then
                      begin
                        ABitrate := '0';
                      end;

                      if Length(ACodec) < 1 then
                      begin
                        ACodec := 'unk';
                      end;

                      if Length(AChannels) < 1 then
                      begin
                        AChannels := '0';
                      end;

                      if Length(ASampleRate) < 1 then
                      begin
                        ASampleRate := '0';
                      end;

                      if Length(ALang) < 1 then
                      begin
                        ALang := 'unk';
                      end;

                      if Length(BitDepth) < 1 then
                      begin
                        BitDepth := 'unk';
                      end;

                      if Length(VideoID) < 1 then
                      begin
                        VideoID := '0';
                        if VideoCount = '0' then
                        begin
                          VideoID := '-1';
                        end;
                      end;

                      AudioID := RemoveNonDigits(FAudioIndexes[i]);

                      // fill new item
                      if i = 0 then
                      begin

                        if IsAudioOnly(FileName) then
                        begin
                          AudioIndexes.Add('0');
                        end
                        else
                        begin
                          AudioIndexes.Add(AudioID);
                        end;

                        NewItemStr := AudioID + ', ' + ACodec + ', ' + ABitrate
                          + ', ' + AChannels + ', ' + ASampleRate + ', ' + ALang
                          + ', ' + IntToTime(FileDuration) + ', ' + BitDepth +
                          ' bit, ' + FileSize;
                        ExtensionLine := ACodec;
                        CopyExtension.Add(ACodec);
                      end
                      else
                      begin

                        if IsAudioOnly(FileName) then
                        begin
                          AudioID := '0';
                        end;

                        NewItemStr := NewItemStr + '|' + AudioID + ', ' + ACodec
                          + ', ' + ABitrate + ', ' + AChannels + ', ' +
                          ASampleRate + ', ' + ALang + ', ' +
                          IntToTime(FileDuration) + ', ' + BitDepth + ' bit, '
                          + FileSize;
                        ExtensionLine := ExtensionLine + ',' + ACodec;
                      end;

                    end;

                    AudioTracks.Add(NewItemStr);
                    Files.Add(FileName);
                    FileList.Items.Add(ExtractFileName(FileName));
                    ExtensionsForCopy.Add(ExtensionLine);

                  end;

                end;

              end;

            end
            else
            begin
              AddToLog(0, 'Cannot add file: ' + FileName +
                ' [No video streams found: ' + VideoCount + ']');
            end;

          end
          else
          begin
            AddToLog(0, 'Cannot add file: ' + FileName +
              ' [Duration is not numeric: ' + VDuration + ']');
          end;

        end
        else
        begin

          AudioTracks.Add('No audio');
          AudioIndexes.Add('-1');

          Files.Add(FileName);

          FileList.Items.Add(ExtractFileName(FileName));

        end;

      finally
        MediaInfo_Close(MediaInfoHandle);
        FileInfo.Free;
        FreeAndNil(FAudioIndexes);
        FileList.Hint := FloatToStr(FileList.Items.Count) + ' file(s)';
      end;

    end;

  end;

end;

procedure TMainForm.AddFiles1Click(Sender: TObject);
var
  i: Integer;
begin

  OpenDialog.InitialDir := LastDirectory;
  AddingStopped := False;
  if OpenDialog.Execute then
  begin

    Self.Enabled := False;
    ProgressForm.show;
    try

      for I := 0 to OpenDialog.Files.Count - 1 do
      begin
        Application.ProcessMessages;

        if AddingStopped then
        begin
          Break;
        end
        else
        begin
          ProgressForm.CurrentFileLabel.Caption :=
            ExtractFileName(OpenDialog.Files[i]);
          AddFile(OpenDialog.Files[i], False);
        end;

      end;

    finally
      Self.Enabled := True;
      ProgressForm.Close;
      Self.BringToFront;
    end;
    LastDirectory := ExtractFileDir(OpenDialog.FileName);
    UpdateListboxScrollBox(FileList);
  end;

end;

procedure TMainForm.AddFolder1Click(Sender: TObject);
var
  Search: TSearchRec;
  FileName: String;
  Extension: String;
begin

  OpenFolderDialog.Directory := LastDirectory;

  if OpenFolderDialog.Execute then
  begin
    SetCurrentDir(OpenFolderDialog.Directory);

    FileList.Items.BeginUpdate;
    Self.Enabled := False;
    ProgressForm.show;
    AddingStopped := False;
    try

      if (FindFirst('*.*', faAnyFile, Search) = 0) then
      Begin
        repeat
          Application.ProcessMessages;

          FileName := GetCurrentDir + '\' + Search.Name;

          Extension := LowerCase(ExtractFileExt(FileName));

          if AddingStopped then
            Break;

          if (Extension = '.mp4') or (Extension = '.mov') or
            (Extension = '.m4v') or (Extension = '.mkv') or
            (Extension = '.mpeg') or (Extension = '.mpg') or
            (Extension = '.flv') or (Extension = '.avi') or (Extension = '.vob')
            or (Extension = '.avs') or (Extension = '.divx') or
            (Extension = '.wmv') or (Extension = '.rmvb') or
            (Extension = '.mp3') or (Extension = '.wav') or (Extension = '.m4a')
            or (Extension = '.flac') or (Extension = '.ogg') or
            (Extension = '.tta') or (Extension = '.mpc') or (Extension = '.aac')
            or (Extension = '.ac3') or (Extension = '.spx') or
            (Extension = '.opus') or (Extension = '.shn') or (Extension = '.wv')
            or (Extension = '.mpc') or (Extension = '.ape') or
            (Extension = '.wma') or (Extension = '.3gp') or (Extension = '.3ga')
            or (Extension = '.m2ts') or (Extension = '.thd') or
            (Extension = '.amr') or (Extension = '.aac') or (Extension = '.m4b')
            or (Extension = '.tak') or (Extension = '.dts') then
          begin
            ProgressForm.CurrentFileLabel.Caption := ExtractFileName(FileName);
            AddFile(FileName, False);
            LastDirectory := ExtractFileDir(FileName);
          end;

        until (FindNext(Search) <> 0) and (not AddingStopped);
        FindClose(Search);
      end;

    finally
      FileList.Items.EndUpdate;
      LastDirectory := OpenFolderDialog.Directory;
      UpdateListboxScrollBox(FileList);

      Self.Enabled := True;
      ProgressForm.Close;
      Self.BringToFront;
    end;

  end;

end;

procedure TMainForm.AddFolderTree1Click(Sender: TObject);
begin

  OpenFolderDialog.Directory := LastDirectory;
  AddingStopped := False;

  if OpenFolderDialog.Execute then
  begin
    FileSearch.RootDirectory := OpenFolderDialog.Directory;

    FileList.Items.BeginUpdate;
    try
      Self.Enabled := False;
      ProgressForm.show;

      LastDirectory := OpenFolderDialog.Directory;

      FileSearch.Search;
    finally
      FileList.Items.EndUpdate;
      UpdateListboxScrollBox(FileList);

      Self.Enabled := True;
      ProgressForm.Close;
      Self.BringToFront;
    end;

  end;

end;

procedure TMainForm.AddToLog(const LogID: ShortInt; const MSG: string);
begin

  case LogID of
    0: // tac log
      begin
        WriteLnToFile(AppData + '\log_main.txt', '[' + DateTimeToStr(Now) +
          '] ' + MSG);
      end;
    // rest are encoder logs
    1:
      begin
        WriteLnToFile(AppData + '\log_encoder1.txt', MSG);
      end;
    2:
      begin
        WriteLnToFile(AppData + '\log_encoder2.txt', MSG);
      end;
    3:
      begin
        WriteLnToFile(AppData + '\log_encoder3.txt', MSG);
      end;
    4:
      begin
        WriteLnToFile(AppData + '\log_encoder4.txt', MSG);
      end;
    5:
      begin
        WriteLnToFile(AppData + '\log_encoder5.txt', MSG);
      end;
    6:
      begin
        WriteLnToFile(AppData + '\log_encoder6.txt', MSG);
      end;
    7:
      begin
        WriteLnToFile(AppData + '\log_encoder7.txt', MSG);
      end;
    8:
      begin
        WriteLnToFile(AppData + '\log_encoder8.txt', MSG);
      end;
    9: // deleted log
      begin
        WriteLnToFile(AppData + '\log_deleted.txt', '[' + DateTimeToStr(Now) +
          '] ' + MSG);
      end;
  end;

end;

procedure TMainForm.AftenEncodeListChange(Sender: TObject);
begin

  if AftenEncodeList.ItemIndex = 0 then
  begin
    AftenQualityEdit.Enabled := True;
    AftenBitrateEdit.Enabled := False;
  end
  else
  begin
    AftenQualityEdit.Enabled := False;
    AftenBitrateEdit.Enabled := True;
  end;

end;

procedure TMainForm.AKEncTAK1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 12;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.ApePercentage(const APEOutput: string): integer;
var
  StrPos1, StrPos2: integer;
  TmpStr: string;
begin

  if Length(APEOutput) > 0 then
  begin
    // log(APEOutput);
    StrPos1 := 10;
    StrPos2 := Pos('%', APEOutput);

    TmpStr := Copy(APEOutput, StrPos1, 3);
    if TmpStr = '100' then
    begin
      Result := 100;
      // Log('progress: ' + TmpStr);
    end
    else if IsStringNumeric(TmpStr) then
    begin
      Result := StrToInt(TmpStr);
      // Log('progress: ' + TmpStr);
    end;
  end
  else
  begin
    // Log('too short');
  end;

end;

procedure TMainForm.AudioCodecBtnClick(Sender: TObject);
begin

  CodecMenu.Popup(AudioCodecBtn.Left + Self.Left + SettingsPanel.Left + 7,
    Self.Top + SettingsPanel.Top + AudioCodecBtn.Top +
    Round(AudioCodecBtn.Height * 3))

end;

procedure TMainForm.AudioEffectsBtnClick(Sender: TObject);
begin

  SoXForm.show;

end;

procedure TMainForm.AudioEncoderListChange(Sender: TObject);
begin

  SetPanelState(AudioEncoderIndex);

end;

procedure TMainForm.AudioMethodListChange(Sender: TObject);
var
  i, j: integer;
  CurrentPanel: TsPanel;
begin

  if AudioMethodList.ItemIndex <> 0 then
  begin

    for I := 0 to SettingsPanel.ControlCount - 1 do
    begin
      if SettingsPanel.Controls[i] is TsPanel then
      begin
        CurrentPanel := TsPanel(SettingsPanel.Controls[i]);
        for j := 0 to CurrentPanel.ControlCount - 1 do
        begin
          CurrentPanel.Controls[j].Enabled := False;
        end;
      end;
      SettingsPanel.Controls[i].Enabled := False;
    end;

    AudioCodecBtn.Enabled := False;
    AudioEffectsBtn.Enabled := False;
    BitDepthList.Enabled := False;
    FAACPanel.Enabled := False;
    QaacPanel.Enabled := False;
    AftenPanel.Enabled := False;
    OggPanel.Enabled := False;
    LamePanel.Enabled := False;
    WavePanel.Enabled := False;
    FLACPanel.Enabled := False;
    FHGPanel.Enabled := False;
    OpusPanel.Enabled := False;
    MPCPanel.Enabled := False;
    MACPanel.Enabled := False;
    TTAPanel.Enabled := False;
    TAKPanel.Enabled := False;
    NeroPanel.Enabled := False;
    AlacPanel.Enabled := False;

  end
  else
  begin

    for I := 0 to SettingsPanel.ControlCount - 1 do
    begin
      if SettingsPanel.Controls[i] is TsPanel then
      begin
        CurrentPanel := TsPanel(SettingsPanel.Controls[i]);
        for j := 0 to CurrentPanel.ControlCount - 1 do
        begin
          CurrentPanel.Controls[j].Enabled := True;
        end;
      end;
      SettingsPanel.Controls[i].Enabled := True;
    end;

    AudioCodecBtn.Enabled := True;
    AudioEffectsBtn.Enabled := True;
    BitDepthList.Enabled := True;
    FAACPanel.Enabled := True;
    QaacPanel.Enabled := True;
    AftenPanel.Enabled := True;
    OggPanel.Enabled := True;
    LamePanel.Enabled := True;
    WavePanel.Enabled := True;
    FLACPanel.Enabled := True;
    FHGPanel.Enabled := True;
    OpusPanel.Enabled := True;
    MPCPanel.Enabled := True;
    MACPanel.Enabled := True;
    TTAPanel.Enabled := True;
    TAKPanel.Enabled := True;
    NeroPanel.Enabled := True;
    AlacPanel.Enabled := True;

    QaacEncodeMethodList.OnChange(Self);
    OggencodeList.OnChange(Self);
    AftenEncodeList.OnChange(Self);
    LameEncodeList.OnChange(Self);
    SameAsSourceBtn.OnClick(Self);
    FHGMethodList.OnChange(Self);
    MPCQualityBar.OnChange(Self);
    NeroMethodList.OnChange(Self);
  end;

  AudioMethodList.Enabled := True;

end;

procedure TMainForm.AudioTrackListChange(Sender: TObject);
var
  StrPos: integer;
  TmpLst: TStringList;
begin

  if AudioTrackList.Items.Count > 0 then
  begin

    if FileList.ItemIndex > -1 then
    begin
      StrPos := Pos(',', AudioTrackList.Text);
      AudioIndexes[FileList.ItemIndex] := Copy(AudioTrackList.Text, 1,
        StrPos - 1);
      TmpLst := TStringList.Create;
      try
        TmpLst.Delimiter := ',';
        TmpLst.StrictDelimiter := True;
        TmpLst.DelimitedText := ExtensionsForCopy[FileList.ItemIndex];

        CopyExtension[FileList.ItemIndex] := TmpLst[AudioTrackList.ItemIndex];
      finally
        FreeAndNil(TmpLst);
      end;

    end;

  end;

end;

procedure TMainForm.ChangeLog1Click(Sender: TObject);
begin
  ShellExecute(Application.Handle, 'open',
    PChar(ExtractFileDir(Application.ExeName) + '\ChangeLog.txt'), nil, nil,
    SW_SHOWNORMAL);

end;

// function TMainForm.CheckOutputFile(const FileIndex: integer): Boolean;
// var
// OutputName: string;
// begin
//
// if FileIndex < FilesToCheck.Count then
// Result := FileExists(FilesToCheck[FileIndex]);
//
// end;

function TMainForm.CheckOutputFiles: Boolean;
var
  i: integer;
  MsgStr: string;
begin

  Result := True;
  MsgStr := '';

  // check each file
  for I := 0 to FilesToCheck.Count - 1 do
  begin

    if (not FileExists(FilesToCheck[i])) then
    begin

      // add to log
      AddToLog(0, 'Cannot find output file ' + FilesToCheck[i]);

      Result := False;

      MsgStr := MsgStr + #10#13 + '-' + ExtractFileName(FilesToCheck[i])

    end;

  end;

  // show a warning to the user
  if Result = False then
  begin
    TrayIcon.Active := True;
    TrayIcon.BalloonHint('TAudioConverter',
      'Following files could not be created: ' + MsgStr + #10#13 + #10#13 +
      'See log for more detail.', btError, 5000);
    if sSkinManager1.Active then
    begin
      sSkinManager1.RepaintForms(True);
    end;
  end
  else
  begin
    // add to log
    AddToLog(0, 'TAudioConverter could locate all the output files');
  end;

end;

function TMainForm.CodecToExtension(const AudioCodec: string): string;
var
  TmpStr: string;
begin

  TmpStr := Trim(AudioCodec);

  if ContainsText(TmpStr, 'vorbis') then
  begin
    Result := '.ogg';
  end
  else if ContainsText(TmpStr, 'mp3') or ContainsText(TmpStr, 'lame') or
    ContainsText(TmpStr, 'mpeg') or ContainsText(TmpStr, 'mpa1l3') then
  begin
    Result := '.mp3';
  end
  else if ContainsText(TmpStr, 'aac') then
  begin
    Result := '.' + LowerCase(SettingsForm.AACExtList.Text);
  end
  else if ContainsText(TmpStr, 'truehd') then
  begin
    Result := '.thd';
  end
  else if ContainsText(TmpStr, 'ac3') then
  begin
    Result := '.ac3';
  end
  else if ContainsText(TmpStr, 'wav') or ContainsText(TmpStr, 'pcm') then
  begin
    Result := '.wav';
  end
  else if ContainsText(TmpStr, 'mp2') then
  begin
    Result := '.mp2';
  end
  else if ContainsText(TmpStr, 'mpa1l2') then
  begin
    Result := '.mp2';
  end
  else if ContainsText(TmpStr, 'amr') then
  begin
    Result := '.amr';
  end
  else if ContainsText(TmpStr, 'flac') then
  begin
    Result := '.flac';
  end;

end;

function TMainForm.CreateArtworkCMD(const FileName: string): string;
var
  ImageFiles: TStringList;
  ImageFile: string;
  Extension: string;
  Search: TSearchRec;
  ArtworkData: ansistring;
  UseExternal: Boolean;
begin

  Result := '';

  // if artwork copying and embeding artwork is selected
  if SettingsForm.ArtworkBtn.Checked and (SettingsForm.ArtworkList.ItemIndex = 1)
  then
  begin
    if FileExists(FileName) then
    begin
      ImageFiles := TStringList.Create;
      try
        // first try embedded artwok
        ArtworkData := GetArtwork(FileName);
        if Length(ArtworkData) > 0 then
        begin
          // extract embedded artwork
          ImageFile := SaveArtwork2(ArtworkData, SettingsForm.TempEdit.Text,
            ChangeFileExt(ExtractFileName(FileName), ''));

          if not FileExists(ImageFile) then
          begin
            UseExternal := False;
          end
          else
          begin
            UseExternal := True;
          end;

        end
        else
        begin
          UseExternal := True;
        end;

        // that means no embedded artwork in source
        if UseExternal then
        begin
          // if cannot extract embedded artwork then
          // try external files
          // get all image files in the file's folder
          SetCurrentDir(ExtractFileDir(FileName));
          if (FindFirst('*.*', faAnyFile, Search) = 0) then
          Begin
            repeat
              Application.ProcessMessages;
              Extension := LowerCase(ExtractFileExt(Search.Name));

              if (Extension = '.png') or (Extension = '.jpeg') or
                (Extension = '.jpg') then
              begin
                if ContainsText(Search.Name, 'FRONT') or
                  ContainsText((Search.Name), 'BACK') or
                  ContainsText((Search.Name), 'DISC') or
                  ContainsText((Search.Name), 'CD') or
                  ContainsText((Search.Name), 'INLAY') or
                  ContainsText((Search.Name), 'CASE') or
                  ContainsText((Search.Name), 'BOX') or
                  ContainsText((Search.Name), 'TRAY') or
                  ContainsText((Search.Name), 'FOLDER') or
                  ContainsText((Search.Name), 'COVER') or
                  ContainsText((Search.Name), 'ALBUM') then
                begin
                  ImageFiles.Add(ExtractFileDir(FileName) + '\' + Search.Name);
                end;
              end;

            until (FindNext(Search) <> 0) and (not AddingStopped);
            FindClose(Search);
          end;

          // if some files found
          if ImageFiles.Count > 0 then
          begin
            ImageFile := ImageFiles[0];
          end
          else
          begin
            ImageFile := '';
          end;
        end;

        // if image file exists, either extracted or external
        // create command line
        if FileExists(ImageFile) then
        begin
          case AudioEncoderIndex of
            0: // ffmpeg aac
              begin
                Result := ' -add-cover:front:"' + ImageFile + '"';
              end;
            1: // qaac
              begin
                Result := ' --cover-art "' + ImageFile + '"';
              end;
            2: // ac3
              begin
                Result := ' ';
              end;
            3: // ogg
              begin
                Result := ' --c "METADATA_BLOCK_PICTURE=' +
                  FileToBase64(ImageFile) + '"';
                Result := ' ';
              end;
            4: // lame
              begin
                Result := ' --ti "' + ImageFile + '"';
              end;
            5: // wav
              begin
                Result := '';
              end;
            6: // flac
              begin
                Result := ' --picture="' + ImageFile + '"';
              end;
            7: // fgh
              begin
                Result := ' -add-cover:front:"' + ImageFile + '"';
              end;
            8: // opus
              begin
                Result := ' --comment "METADATA_BLOCK_PICTURE=' +
                  FileToBase64(ImageFile) + '"';
                Result := ' ';
              end;
            9: // mpc
              begin
                Result := ' ';
              end;
            10: // ape
              begin
                Result := ' ';
              end;
            11: // tta
              begin
                Result := ' ';
              end;
            12: // tak
              begin
                // Result := ' -tt ARTIST="' + Artist + '" -tt TITLE="' + Title +
                // '" -tt ALBUM="' + Album + '" -tt GENRE="' + Genre +
                // '" -tt COMPOSER="' + Composer + '" -tt YEAR="' + RecordDate +
                // '" -tt TRACK="' + TrackNo + '" -tt COMMENT="' + Comment + '"';;
                Result := ' ';
              end;
            13: // nero
              begin
                Result := ' -add-cover:front:"' + ImageFile + '"';
              end;
            14: // alac
              begin
                Result := ' --artwork "' + ImageFile + '"';
              end;
            15: // wmaencoder
              begin
                Result := ' ';
              end;
            16: // wavpack
              begin
                Result := '  --write-binary-tag cover="' + ImageFile + '"';
                Result := ' ';
              end;
          end;
        end;
      finally
        FreeAndNil(ImageFiles);
      end;
    end;
  end;

end;

function TMainForm.CreateBitDepthCMD(const FileName: string): string;
var
  MediaInfoHandle: Cardinal;
  BitDepth: string;
begin

  Result := ' ';

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '1');

        BitDepth := Trim(MediaInfo_Get(MediaInfoHandle, Stream_Audio, 0,
          'BitDepth', Info_Text, Info_Name));

        if Length(BitDepth) < 1 then
        begin
          Result := ' ';
        end
        else
        begin
          if BitDepth = '8' then
          begin
            Result := ' ';
          end
          else if BitDepth = '16' then
          begin
            Result := '-acodec pcm_s16le';
          end
          else if BitDepth = '24' then
          begin
            Result := '-acodec pcm_s24le';
          end
          else if BitDepth = '32' then
          begin
            Result := '-acodec pcm_s32le';
          end;

        end;

      finally
        MediaInfo_Close(MediaInfoHandle);
      end;

    end;

  end;

end;

procedure TMainForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.WinClassName := SWindowClassName;
end;

function TMainForm.CreateTagCMD(const FileName: string): string;
var
  MediaInfoHandle: Cardinal;
  Title, Artist, Genre, TrackNo, Performer, RecordDate, Composer, Album: string;
  Comment: string;
  ArtistSort, AlbumSort, ComposerSort, AlbumArtistSort, NameSort: string;
  TrackTotal: string;
  AlbumArtist: string;
begin

  Result := ' ';
  if SettingsForm.TagsBtn.Checked = False then Exit;

  Title := '';
  Artist := '';
  Genre := '';
  TrackNo := '';
  RecordDate := '';
  TrackTotal := '';

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '1');

        Title := MediaInfo_Get(MediaInfoHandle, Stream_General, 0, 'Title',
          Info_Text, Info_Name);
        Artist := MediaInfo_Get(MediaInfoHandle, Stream_General, 0, 'Performer',
          Info_Text, Info_Name);
        Genre := MediaInfo_Get(MediaInfoHandle, Stream_General, 0, 'Genre',
          Info_Text, Info_Name);
        TrackNo := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Track/Position', Info_Text, Info_Name);
        TrackTotal := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Track/Position_Total', Info_Text, Info_Name);
        Performer := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Album/Performer', Info_Text, Info_Name);
        RecordDate := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Recorded_Date', Info_Text, Info_Name);
        Composer := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Composer', Info_Text, Info_Name);
        Album := MediaInfo_Get(MediaInfoHandle, Stream_General, 0, 'Album',
          Info_Text, Info_Name);
        Comment := MediaInfo_Get(MediaInfoHandle, Stream_General, 0, 'Comment',
          Info_Text, Info_Name);
        ArtistSort := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'ARTISTSORT', Info_Text, Info_Name);
        AlbumSort := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'ALBUMSORT', Info_Text, Info_Name);
        ComposerSort := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'COMPOSERSORT', Info_Text, Info_Name);
        AlbumArtistSort := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'ALBUMARTISTSORT', Info_Text, Info_Name);
        NameSort := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'NAMESORT', Info_Text, Info_Name);
        //
        AlbumArtist := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Album/Performer', Info_Text, Info_Name);

        if Length(Artist) < 1 then
        begin
          if Length(Performer) > 0 then
          begin
            Artist := Performer;
          end;
        end;

        Title := RemoveQuotation(Title);
        Artist := RemoveQuotation(Artist);
        Genre := RemoveQuotation(Genre);
        TrackNo := RemoveQuotation(TrackNo);
        TrackTotal := RemoveQuotation(TrackTotal);
        Performer := RemoveQuotation(Performer);
        RecordDate := RemoveQuotation(RecordDate);
        Composer := RemoveQuotation(Composer);
        Album := RemoveQuotation(Album);
        Comment := RemoveQuotation(Comment);
        ArtistSort := RemoveQuotation(ArtistSort);
        AlbumSort := RemoveQuotation(AlbumSort);
        ComposerSort := RemoveQuotation(ComposerSort);
        AlbumArtistSort := RemoveQuotation(AlbumArtistSort);
        NameSort := RemoveQuotation(NameSort);
        AlbumArtist := RemoveQuotation(AlbumArtist);

        case AudioEncoderIndex of
          0: // ffmpeg aac (nerotag)
            begin
              Result := '-meta:artist="' + Artist + '" -meta:title="' + Title +
                '" -meta:genre="' + Genre + '" -meta:composer="' + Composer +
                '" -meta:album="' + Album + '" -meta:year="' + RecordDate +
                '" -meta:comment="' + Comment + '"';
            end;
          1: // qaac
            begin
              Result := ' --artist "' + Artist + '" --title "' + Title +
                '" --genre "' + Genre + '" --composer "' + Composer +
                '" --album "' + Album + '" --track "' + TrackNo + '" --date "' +
                RecordDate + '" --band "' + AlbumArtist + '" --tag "cmt:' +
                Comment + '" ';
              if Length(ArtistSort) > 1 then
              begin
                Result := Result + ' --tag "soar:' + ArtistSort + '"';
              end;
              if Length(AlbumSort) > 1 then
              begin
                Result := Result + ' --tag "soal:' + AlbumSort + '"';
              end;
              if Length(ComposerSort) > 1 then
              begin
                Result := Result + ' --tag "soco:' + ComposerSort + '"';
              end;
              if Length(AlbumArtistSort) > 1 then
              begin
                Result := Result + ' --tag "soaa:' + AlbumArtistSort + '"';
              end;
              if Length(NameSort) > 1 then
              begin
                Result := Result + ' --tag "sonm:' + NameSort + '"';
              end;
              if Length(NameSort) > 1 then
              begin
                Result := Result + ' --tag "sonm:' + NameSort + '"';
              end;
            end;
          2: // ac3
            begin
              Result := ' ';
            end;
          3: // ogg
            begin
              Result := ' --utf8 -a "' + Artist + '" -t "' + Title + '" -l "' +
                Album + '" --genre "' + Genre + '" -d "' + RecordDate + '" -N "'
                + TrackNo + '" -c "comment=' + Comment + '"';
            end;
          4: // lame
            begin
              Result := ' --ta "' + Artist + '" --tt "' + Title + '" --tg "' +
                Genre + '" --tl "' + Album + '" --ty "' + RecordDate +
                '" --tn "' + TrackNo + '" --tc "' + Comment + '"';
            end;
          5: // wav
            begin
              Result := '';
            end;
          6: // flac
            begin
              Result := ' --tag=artist="' + Artist + '" --tag=title="' + Title +
                '" --tag=genre="' + Genre + '" --tag=composer="' + Composer +
                '" --tag=album="' + Album + '" --tag=date="' + RecordDate +
                '" --tag=TRACKNUMBER="' + TrackNo + '" --tag=comment="' +
                Comment + '"';
            end;
          7: // fgh
            begin
              Result := '-meta:artist="' + Artist + '" -meta:title="' + Title +
                '" -meta:genre="' + Genre + '" -meta:composer="' + Composer +
                '" -meta:album="' + Album + '" -meta:year="' + RecordDate +
                '" -meta:comment="' + Comment + '"';
            end;
          8: // opus
            begin
              Result := ' --artist "' + Artist + '" --title "' + Title +
                '" --comment "genre=' + Genre + '" --comment "composer=' +
                Composer + '" --comment "album=' + Album + '" --comment "date='
                + RecordDate + '" --comment "TRACKNUMBER=' + TrackNo +
                '" --comment "comment=' + Comment + '"';
            end;
          9: // mpc
            begin
              // Result := ' --artist "' + Artist + '" --title "' + Title +
              // '" --tag "genre"="' + Genre + '" --tag "composer"="' +
              // Composer + '" --tag  "album"="' + Album + '" --tag "date"="'
              // + RecordDate + '" --tag "TRACKNUMBER"="' + TrackNo +
              // '" --tag "comment"="' + Comment + '"';
              Result := ' --ape2 --artist "' + Artist + '" --title "' + Title +
                '" --album "' + Album + '" --year "' + RecordDate +
                '" --track "' + TrackNo + '" --genre "' + Genre +
                '" --comment "' + Comment + '"'
              // Result := ' --ape2 -T "TITLE='+ Title + '" -T "ARTIST=' + Performer +
              // '" -T "ALBUMARTIST=' + Artist + '" -T "ALBUM=' + Album +
              // '" -T "DATE=' + RecordDate + '" -T "TRACKNUMBER=' + TrackNo +
              // '" -T "GENRE=' + Genre + '" -T "COMMENT=' + Comment + '" -T "COMPOSER=' + Composer + '"'
            end;
          10: // ape
            begin
              Result := ' ';
            end;
          11: // tta
            begin
              Result := ' ';
            end;
          12: // tak
            begin
              // Result := ' -tt ARTIST="' + Artist + '" -tt TITLE="' + Title +
              // '" -tt ALBUM="' + Album + '" -tt GENRE="' + Genre +
              // '" -tt COMPOSER="' + Composer + '" -tt YEAR="' + RecordDate +
              // '" -tt TRACK="' + TrackNo + '" -tt COMMENT="' + Comment + '"';;
              Result := ' ';
            end;
          13: // nero
            begin
              Result := '-meta:artist="' + Artist + '" -meta:title="' + Title +
                '" -meta:genre="' + Genre + '" -meta:composer="' + Composer +
                '" -meta:album="' + Album + '" -meta:year="' + RecordDate +
                '" -meta:comment="' + Comment + '"';
            end;
          14: // alac
            begin
              Result := ' --artist "' + Artist + '" --title "' + Title +
                '" --genre "' + Genre + '" --composer "' + Composer +
                '" --album "' + Album + '" --track "' + TrackNo + '" --date "' +
                RecordDate + '" --band "' + AlbumArtist + '" --tag "cmt:' +
                Comment + '" ';
              if Length(ArtistSort) > 1 then
              begin
                Result := Result + ' --tag "soar:' + ArtistSort + '"';
              end;
              if Length(AlbumSort) > 1 then
              begin
                Result := Result + ' --tag "soal:' + AlbumSort + '"';
              end;
              if Length(ComposerSort) > 1 then
              begin
                Result := Result + ' --tag "soco:' + ComposerSort + '"';
              end;
              if Length(AlbumArtistSort) > 1 then
              begin
                Result := Result + ' --tag "soaa:' + AlbumArtistSort + '"';
              end;
              if Length(NameSort) > 1 then
              begin
                Result := Result + ' --tag "sonm:' + NameSort + '"';
              end;
              if Length(NameSort) > 1 then
              begin
                Result := Result + ' --tag "sonm:' + NameSort + '"';
              end;
            end;
          15: // wmaencoder
            begin
              Result := ' --artist "' + Artist + '" --title "' + Title +
                '" --genre "' + Genre + '" --composer "' + Composer +
                '" --album "' + Album + '" --tracknumber "' + TrackNo +
                '" --year "' + RecordDate + '" --comment "' + Comment + '"';
            end;
          16: // wavpack
            begin
              Result := ' -w "artist=' + Artist + '" -w "title=' + Title +
                '" -w "genre=' + Genre + '" -w "composer=' + Composer +
                '" -w "album=' + Album + '" -w "year=' + RecordDate +
                '" -w "track=' + TrackNo + '" -w "comment=' + Comment + '"';

            end;
        end;

      finally
        MediaInfo_Close(MediaInfoHandle);
        Result := Result + CreateArtworkCMD(FileName)
      end;

    end;

  end;

end;

function TMainForm.DecideNumOfProcesses: integer;
var
  CPUCount: integer;
begin

  CPUCount := SystemInfo.CPU.ProcessorCount;

  if CPUCount > 4 then
  begin

    if CPUCount < 9 then
    begin
      Result := 6;
    end
    else
    begin
      Result := 8;
    end;

  end
  else
  begin
    Result := SystemInfo.CPU.ProcessorCount;
  end;

end;

procedure TMainForm.DeleteLogs;
begin

  if FileExists(AppData + '\log_main.txt') then
  begin
    DeleteFile(AppData + '\log_main.txt')
  end;

  if FileExists(AppData + '\log_encoder1.txt') then
  begin
    DeleteFile(AppData + '\log_encoder1.txt')
  end;

  if FileExists(AppData + '\log_encoder2.txt') then
  begin
    DeleteFile(AppData + '\log_encoder2.txt')
  end;

  if FileExists(AppData + '\log_encoder3.txt') then
  begin
    DeleteFile(AppData + '\log_encoder3.txt')
  end;

  if FileExists(AppData + '\log_encoder4.txt') then
  begin
    DeleteFile(AppData + '\log_encoder4.txt')
  end;

  if FileExists(AppData + '\log_encoder5.txt') then
  begin
    DeleteFile(AppData + '\log_encoder5.txt')
  end;

  if FileExists(AppData + '\log_encoder6.txt') then
  begin
    DeleteFile(AppData + '\log_encoder6.txt')
  end;

  if FileExists(AppData + '\log_encoder7.txt') then
  begin
    DeleteFile(AppData + '\log_encoder7.txt')
  end;

  if FileExists(AppData + '\log_encoder8.txt') then
  begin
    DeleteFile(AppData + '\log_encoder8.txt')
  end;

  if FileExists(AppData + '\log_deleted.txt') then
  begin
    DeleteFile(AppData + '\log_deleted.txt')
  end;

end;

procedure TMainForm.DeleteTempFiles;
var
  Search: TSearchRec;
  i: Integer;
  DeletedCount: Integer;
begin

  AddToLog(0, ' Started deleting temp files...');
  AddToLog(0, ' Temp Folder: ' + SettingsForm.TempEdit.Text);

  DeletedCount := 0;

  // clear temp folder
  SetCurrentDir(SettingsForm.TempEdit.Text);
  if (FindFirst('*.*', faAnyFile, Search) = 0) then
  Begin
    repeat
      Application.ProcessMessages;

      if FileExists(GetCurrentDir + '\' + Search.Name) then
      begin

        if GetCurrentDir <> ExtractFileDir(Application.ExeName) then
        begin
          if not DeleteFile(GetCurrentDir + '\' + Search.Name) then
          begin
            AddToLog(9, 'Can''t delete: ' + Search.Name);
          end
          else
          begin
            Inc(DeletedCount);
            AddToLog(9, 'Deleted: ' + GetCurrentDir + '\' + Search.Name);
          end;
        end;

      end;

    until (FindNext(Search) <> 0);
    FindClose(Search);
  end;

  AddToLog(0, ' Deleted ' + IntToStr(DeletedCount) + ' file(s).');
  AddToLog(0, 'Finished deleting temp files.');
  AddToLog(0, '');

end;

procedure TMainForm.DisableUI;
var
  i: integer;
begin

  StartBtn.Enabled := False;
  StopBtn.Enabled := True;
  DirectoryEdit.Enabled := False;
  SameAsSourceBtn.Enabled := False;
  ProgressPanel.Visible := True;
  ProgressPanel.BringToFront;

  DragDrop.DropTarget := nil;

  for I := 0 to MainMenu.Items.Count - 1 do
  begin
    MainMenu.Items.Items[i].Enabled := False;
  end;

  ProgressBar1.Progress := 0;
  ProgressBar2.Progress := 0;
  ProgressBar3.Progress := 0;
  ProgressBar4.Progress := 0;
  ProgressBar5.Progress := 0;
  ProgressBar6.Progress := 0;
  ProgressBar7.Progress := 0;
  ProgressBar8.Progress := 0;

  ProgressBar1.Suffix := '%';
  ProgressBar2.Suffix := '%';
  ProgressBar3.Suffix := '%';
  ProgressBar4.Suffix := '%';
  ProgressBar5.Suffix := '%';
  ProgressBar6.Suffix := '%';
  ProgressBar7.Suffix := '%';
  ProgressBar8.Suffix := '%';

  Self.Repaint;
end;

procedure TMainForm.DonationBtnClick(Sender: TObject);
var
  MSG: string;
begin

  MSG := 'TAudioConverter will now take you to its homepage where you can use "Donate" button to make a donation using Paypal to this project.'
    + sLineBreak + sLineBreak + 'Thank you for considering making a donation!';
  Application.MessageBox(PChar(MSG), 'Donation', MB_ICONINFORMATION);
  ShellExecute(0, 'open', 'http://taudioconverter.sourceforge.net/', nil, nil,
    SW_SHOWNORMAL);

end;

procedure TMainForm.DownBtnClick(Sender: TObject);
var
  i: Integer;
begin

  for i := FileList.Items.Count - 1 downto 0 do
  begin

    if i < FileList.Items.Count then
    begin

      if FileList.Selected[i] then
      begin
        FileList.Items.Exchange(i, i + 1);
        FileList.Selected[i + 1] := True;
        Durations.Exchange(i, i + 1);
        AudioTracks.Exchange(i, i + 1);
        AudioIndexes.Exchange(i, i + 1);
        Files.Exchange(i, i + 1);
        ExtensionsForCopy.Exchange(i, i + 1);
        CopyExtension.Exchange(i, i - 1);
      end;

    end;

  end;

end;

procedure TMainForm.DownloadNeroAACTools1Click(Sender: TObject);
begin
ShellExecute(Application.Handle, 'open',
    'http://www.nero.com/enu/company/about-nero/nero-aac-codec.php', nil, nil,
    SW_SHOWNORMAL);
end;

procedure TMainForm.DragDropDrop(Sender: TObject; Pos: TPoint; Value: TStrings);
var
  i: Integer;
  Extension: string;
  DirectoriesToSearch: TStringList;
begin

  Self.Enabled := False;
  ProgressForm.show;
  AddingStopped := False;
  DirectoriesToSearch := TStringList.Create;
  try

    for i := 0 to Value.Count - 1 do
    begin
      Application.ProcessMessages;

      Extension := LowerCase(ExtractFileExt(Value[i]));

      if AddingStopped then
      begin
        Break;
      end
      else
      begin
        // decide if file or directory
        if DirectoryExists(Value[i]) then
        begin
          DirectoriesToSearch.Add(Value[i]);
        end
        else
        begin
          if (Extension = '.mp4') or (Extension = '.mov') or
            (Extension = '.m4v') or (Extension = '.mkv') or
            (Extension = '.mpeg') or (Extension = '.mpg') or
            (Extension = '.flv') or (Extension = '.avi') or (Extension = '.vob')
            or (Extension = '.avs') or (Extension = '.divx') or
            (Extension = '.wmv') or (Extension = '.rmvb') or
            (Extension = '.mp3') or (Extension = '.wav') or (Extension = '.m4a')
            or (Extension = '.flac') or (Extension = '.ogg') or
            (Extension = '.tta') or (Extension = '.mpc') or (Extension = '.aac')
            or (Extension = '.ac3') or (Extension = '.spx') or
            (Extension = '.opus') or (Extension = '.shn') or (Extension = '.wv')
            or (Extension = '.mpc') or (Extension = '.ape') or
            (Extension = '.wma') or (Extension = '.3gp') or (Extension = '.3ga')
            or (Extension = '.m2ts') or (Extension = '.thd') or
            (Extension = '.amr') or (Extension = '.aac') or (Extension = '.m4b')
            or (Extension = '.tak') or (Extension = '.dts') then
          begin
            AddFile(Value[i], False);
            ProgressForm.CurrentFileLabel.Caption := ExtractFileName(Value[i]);
            LastDirectory := ExtractFileDir(Value[i]);
          end;

        end;

      end;

    end;

    FileList.Items.BeginUpdate;
    try
      // add directory content
      if DirectoriesToSearch.Count > 0 then
      begin

        for I := 0 to DirectoriesToSearch.Count - 1 do
        begin
          Application.ProcessMessages;

          FileSearch.RootDirectory := DirectoriesToSearch[i];
          FileSearch.Search;

          LastDirectory := DirectoriesToSearch[i];
        end;

      end;
    finally
      FileList.Items.EndUpdate;
    end;

  finally
    Self.Enabled := True;
    ProgressForm.Close;
    Self.BringToFront;
    FreeAndNil(DirectoriesToSearch);
    UpdateListboxScrollBox(FileList);
  end;

end;

procedure TMainForm.EmalBtnClick(Sender: TObject);
const
  NewLine = '%0D%0A';
var
  mail: PChar;
  mailbody: string;
begin

  mailbody := AboutForm.Label1.Caption + NewLine + NewLine + 'Bugs: ' + NewLine
    + NewLine + NewLine + 'Suggestions: ' + NewLine + NewLine + NewLine;
  mail := PwideChar('mailto:ozok26@gmail.com?subject=TAudioConverter&body=' +
    mailbody);

  ShellExecute(0, 'open', mail, nil, nil, SW_SHOWNORMAL);

end;

procedure TMainForm.EnableUI;
var
  i: integer;
begin

  StartBtn.Enabled := True;
  StopBtn.Enabled := False;
  DirectoryEdit.Enabled := True;
  SameAsSourceBtn.Enabled := True;
  ProgressPanel.Visible := False;
  ProgressPanel.SendToBack;

  for I := 0 to MainMenu.Items.Count - 1 do
  begin
    MainMenu.Items.Items[i].Enabled := True;
  end;
  DragDrop.DropTarget := MainForm;

  OutputBtn.Top := DirectoryEdit.Top;

end;

procedure TMainForm.Exit1Click(Sender: TObject);
begin

  Application.Terminate;

end;

procedure TMainForm.FAACAAC1Click(Sender: TObject);
begin
  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 0;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.FAACPercentage(const FAACOutput: string): Integer;
var
  StrPos1, StrPos2: Integer;
  FConsoleOutput: string;
begin

  FConsoleOutput := Trim(FAACOutput);

  if Length(FConsoleOutput) > 0 then
  begin
    StrPos1 := Pos('(', FConsoleOutput);
    StrPos2 := Pos('%)|', FConsoleOutput);

    if StrPos2 > StrPos1 then
    begin
      FConsoleOutput := Trim(Copy(FConsoleOutput, StrPos1 + 1,
        StrPos2 - StrPos1 - 1));
    end;

    if IsStringNumeric(FConsoleOutput) then
    begin
      Result := StrToInt(FConsoleOutput);
    end

  end;

end;

procedure TMainForm.FFMpegAC31Click(Sender: TObject);
begin
  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 2;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.FFMpegPercentage(const FFMpegOutput: string;
  const DurationStr: string): Integer;
var
  pos1: Integer;
  pos2: Integer;
  Text: String;
  prog: String;
  last: String;
  PositionInt: Integer;
begin

  if (Length(FFMpegOutput) > 0) then
  begin
    Text := FFMpegOutput;
    // pos1 := Pos('frame=', FFmpegOutput);
    // pos2 := Pos('fps=', FFmpegOutput);
    // prog := Copy(Text, pos1 + 1, (pos2 - pos1 - 1));
    // last := Copy(prog, 6, Length(prog) - 4);
    pos1 := Pos('time=', FFMpegOutput);
    pos2 := Pos('bitrate=', FFMpegOutput);
    prog := Copy(Text, pos1 + 1, (pos2 - pos1 - 1));
    last := Copy(prog, 5, Length(prog) - 4);

    PositionInt := TimeToInt(LeftBStr(Trim(last), 8));

    if IsStringNumeric(DurationStr) then
    begin
      if (StrToInt(DurationStr) > 0) then
      begin
        Result := (100 * PositionInt) div StrToInt(DurationStr);
      end;
    end;

  end;

end;

procedure TMainForm.FFMpegWAV1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 5;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.FhgaacencAAC1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 7;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.FHGMethodListChange(Sender: TObject);
begin

  if FHGMethodList.ItemIndex = 0 then
  begin
    FHGBitrateEdit.Enabled := True;
    FHGQualityEdit.Enabled := False;
    FHGProfileList.Enabled := True;
  end
  else
  begin
    FHGBitrateEdit.Enabled := False;
    FHGQualityEdit.Enabled := True;
    FHGProfileList.Enabled := False;
  end;

end;

procedure TMainForm.FileListAdvancedCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
  var DefaultDraw: Boolean);
begin

  if (Item.Index mod 2) = 0 then
  begin
    Sender.Canvas.Font.Color := clBlack;
  end
  else
  begin
    Sender.Canvas.Font.Color := clGrayText;
  end;

end;

procedure TMainForm.FileListClick(Sender: TObject);
var
  index: Integer;
  StrPos: integer;
  i: integer;
begin

  index := FileList.ItemIndex;

  AudioTrackList.Items.Clear;

  if index > -1 then
  begin
    AudioTrackList.Items.DelimitedText := AudioTracks[index];

    if AudioTrackList.Items.Count > 0 then
    begin

      for I := 0 to AudioTrackList.Items.Count - 1 do
      begin
        Application.ProcessMessages;

        StrPos := Pos(',', AudioTrackList.Items[i]);
        if AudioIndexes[index] = Copy(AudioTrackList.Items[i], 1, StrPos - 1)
        then
        begin
          AudioTrackList.ItemIndex := i;
        end
        else
        begin
          AudioTrackList.ItemIndex := 0;
        end;

      end;

    end;

    DirecortyLabel.Caption := Files[index];
  end
  else
  begin
    AudioTrackList.Items.Clear;
    DirecortyLabel.Caption := '';
  end;

end;

procedure TMainForm.FileListDrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin

  if (Control as TsListBox).Items.Count < 1 then
    Exit;

  with Control as TsListBox, Canvas do
  begin

    // item selected
    if odSelected in State then
    begin

      Brush.Color := Self.Color;
      Font.Color := clBlack;
      FillRect(Rect);
      TextOut(Rect.Left + 2, Rect.Top + 2, Items[Index])

    end
    else
    begin
      // item not selected
      Brush.Color := (Control as TsListBox).Color;
      Font.Color := (Control as TsListBox).Font.Color;
      FillRect(Rect);
      TextOut(Rect.Left + 2, Rect.Top + 2, Items[Index])
    end;

  end;

end;

procedure TMainForm.FileListKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

  if (Key = VK_UP) or (Key = VK_DOWN) then
  begin
    FileList.OnClick(Self);
  end;

end;

procedure TMainForm.FileSearchFindFile(Sender: TObject; const AName: string);
begin

  ProgressForm.CurrentFileLabel.Caption := ExtractFileName(AName);
  AddFile(AName, False);

end;

procedure TMainForm.FileSearchProgress(Sender: TObject);
begin

  Application.ProcessMessages;

end;

function TMainForm.FileToBase64(const FileName: string): ansistring;
var
  stream: TMemoryStream;
begin
  stream := TMemoryStream.Create;
  try
    stream.LoadFromFile(FileName);
    Result := EncodeBase64(stream.Memory, stream.Size);
  finally
    stream.Free;
  end;

end;

procedure TMainForm.FillProgressList;
begin

end;

procedure TMainForm.FillSummaryList;
var
  NewNode: TTreeNode;
  i: integer;
begin

  SummaryView.Items.Clear;

  with SummaryView.Items do
  begin
    // number of processes
    NewNode := AddChild(nil, 'Number of processes: ' +
      FloatToStr(SettingsForm.ProcessCountList.ItemIndex + 1));
    AddChild(nil, 'Copy tags: ' +
      BoolToStr(SettingsForm.TagsBtn.Checked, True));
    AddChild(nil, 'Enable artwork: ' +
      BoolToStr(SettingsForm.ArtworkBtn.Checked, True));
    if SettingsForm.ArtworkList.ItemIndex = 0 then
    begin
      AddChild(nil, 'Copy artwork to output: True');
      AddChild(nil, 'Copy external artwork: ' +
        BoolToStr(SettingsForm.Artwork2Btn.Checked, True));
    end
    else
    begin
      AddChild(nil, 'Embeded to output file: True');
    end;
    AddChild(nil, 'Download lyric: ' +
      BoolToStr(SettingsForm.LyricBtn.Checked, True));
    AddChild(nil, 'Add encoder suffix: ' +
      BoolToStr(SettingsForm.FolderSuffixBtn.Checked, True));
    // audio
    NewNode := AddChild(nil, 'Audio');
    case AudioMethodList.ItemIndex of
      0:
        begin
          // codec
          case AudioEncoderIndex of
            0:
              begin
                AddChild(NewNode, 'Encoder: FFMpeg AAC');
                AddChild(NewNode, 'Bitrate: ' + FAACBitrateEdit.Text + ' kbps');

              end;
            1:
              begin
                AddChild(NewNode, 'Encoder: QAAC');
                case QaacEncodeMethodList.ItemIndex of
                  0:
                    AddChild(NewNode, 'ABR: ' + QaacBitrateEdit.Text + ' kbps');
                  1:
                    AddChild(NewNode, 'TVBR: ' + QaacvQualityEdit.Text);
                  2:
                    AddChild(NewNode, 'CVBR: ' + QaacBitrateEdit.Text +
                      ' kbps');
                  3:
                    AddChild(NewNode, 'CBR: ' + QaacBitrateEdit.Text + ' kbps');
                end;
                AddChild(NewNode, 'Encoding quality: ' + QaacQualityList.Text);
                AddChild(NewNode, 'HE AAC mode: ' +
                  BoolToStr(QaacHEBtn.Checked, True));
              end;
            2:
              begin
                AddChild(NewNode, 'Encoder: FFMpeg AC3');
                case AftenEncodeList.ItemIndex of
                  0:
                    AddChild(NewNode, 'Quality: ' + AftenQualityEdit.Text);
                  1:
                    AddChild(NewNode, 'CBR: ' + AftenBitrateEdit.Text +
                      ' kbps');
                end;
              end;
            3:
              begin
                AddChild(NewNode, 'Encoder: Ogg Vorbis');
                case OggencodeList.ItemIndex of
                  0:
                    AddChild(NewNode, 'Quality: ' + OggQualityEdit.Text);
                  1:
                    begin
                      AddChild(NewNode, 'Bitrate: ' + OggBitrateEdit.Text
                        + ' kbps');
                      AddChild(NewNode, 'Managed bitrate: ' +
                        BoolToStr(OggManagedBitrateBtn.Checked, True));
                    end;
                end;
              end;
            4:
              begin
                AddChild(NewNode, 'Encoder: Lame');
                case LameEncodeList.ItemIndex of
                  0:
                    AddChild(NewNode, 'CBR: ' + LameBitrateEdit.Text + ' kbps');
                  1:
                    AddChild(NewNode, 'ABR: ' + LameBitrateEdit.Text + ' kbps');
                  2:
                    AddChild(NewNode, 'VBR: ' + LameVBREdit.Text);
                end;
                AddChild(NewNode, 'Algorithm quality: ' + LameQualityEdit.Text);
              end;
            5:
              begin
                AddChild(NewNode, 'Encoder: Wav');
              end;
            6:
              begin
                AddChild(NewNode, 'Encoder: FLAC');
                AddChild(NewNode, 'Compression Level: ' +
                  FloatToStr(FLACCompList.ItemIndex));
                if FLACEMSBtn.Checked then
                begin
                  AddChild(NewNode, 'Exhaustive model search: True');
                end
                else
                begin
                  AddChild(NewNode, 'Exhaustive model search: False');
                end;
              end;
            7:
              begin
                AddChild(NewNode, 'Encoder: FHG AAC');
                case FHGMethodList.ItemIndex of
                  0:
                    begin
                      AddChild(NewNode, 'CBR: ' + FHGBitrateEdit.Text +
                        ' kbps');
                      AddChild(NewNode, 'Profile: ' + FHGProfileList.Text);
                    end;
                  1:
                    AddChild(NewNode, 'VBR: ' + FHGQualityEdit.Text);
                end;
              end;
            8:
              begin
                AddChild(NewNode, 'Encoder: Opus');
                case OpusEncodeMethodList.ItemIndex of
                  0:
                    AddChild(NewNode, 'VBR: ' + OpusBitrateEdit.Text + ' kbps');
                  1:
                    AddChild(NewNode, 'CVBR: ' + OpusBitrateEdit.Text);
                  2:
                    AddChild(NewNode, 'CBR: ' + OpusBitrateEdit.Text);
                end;
                AddChild(NewNode, 'Complexity: ' + OpusCompEdit.Text);
              end;
            9:
              begin
                AddChild(NewNode, 'Encoder: MPC');
                AddChild(NewNode, 'Quality: ' + MPCQualityEdit.Text);
              end;
            10:
              begin
                AddChild(NewNode, 'Encoder: Monkey''s Audio');
                AddChild(NewNode, 'Compression Level: ' + MACLevelList.Text);
              end;
            11:
              begin
                AddChild(NewNode, 'Encoder: TTA');
              end;
            12:
              begin
                AddChild(NewNode, 'Encoder: TAK');
                AddChild(NewNode, 'Preset: ' + TAKPresetList.Text);
              end;
            13:
              begin
                AddChild(NewNode, 'Encoder: Nero AAC');
                case NeroMethodList.ItemIndex of
                  0:
                    AddChild(NewNode, 'Quality: ' + NeroQualityEdit.Text);
                  1:
                    AddChild(NewNode, 'ABR: ' + NeroBitrateEdit.Text + ' kbps');
                  2:
                    AddChild(NewNode, 'CBR: ' + NeroBitrateEdit.Text + ' kbps');
                end;
                AddChild(NewNode, 'Profile: ' + NeroProfileList.Text);
              end;
            14:
              begin
                AddChild(NewNode, 'Encoder: ALAC');
              end;
            15:
              begin
                AddChild(NewNode, 'Encoder: WMAEncoder');
                case WMAMethodList.ItemIndex of
                  0:
                    AddChild(NewNode, 'Quality: ' + WMAQualityList.Text);
                  1:
                    AddChild(NewNode, 'Bitrate: ' + WMABitrateEdit.Text);
                end;
                AddChild(NewNode, 'Codec: ' + WMACodecList.Text);
              end;
            16:
              begin
                AddChild(NewNode, 'Encoder: WavPack');
                case WavPackMethodList.ItemIndex of
                  0:
                    AddChild(NewNode, 'Lossless');
                  1:
                    begin
                      AddChild(NewNode, 'Hybrid: ' + WavPackBitrateEdit.Text
                        + ' kbps');
                      AddChild(NewNode, 'Create correction file: ' +
                        BoolToStr(WavPackCorrectionBtn.Checked, True));
                    end;
                end;
                AddChild(NewNode, 'Extra encode processing: ' +
                  BoolToStr(WavPackExtraBtn.Checked, True));
              end;
          end;
          AddChild(NewNode, 'Bit Depth: ' + BitDepthList.Text);
          NewNode.Expand(True);
          // effects
          with SoXForm do
          begin
            NewNode := AddChild(NewNode, 'Effects');
            if EnableBtn.Checked then
            begin
              AddChild(NewNode, 'Normalize: ' +
                BoolToStr(NormBtn.Checked, True));
              if VolumeBtn.Checked then
              begin
                AddChild(NewNode, 'Change volume: ' +
                  BoolToStr(VolumeBtn.Checked, True));
                AddChild(NewNode, 'Volume: ' + VolumeEdit.Text);
              end
              else
              begin
                AddChild(NewNode, 'Change volume: ' +
                  BoolToStr(VolumeBtn.Checked, True));
              end;

              AddChild(NewNode, 'Multithreaded: ' +
                BoolToStr(ThreadBtn.Checked, True));
              AddChild(NewNode, 'Samplerate: ' + SampleList.Text);
              AddChild(NewNode, 'Channels: ' + ChannelList.Text);
              NewNode.Expand(True)
            end
            else
            begin
              AddChild(NewNode, 'Disabled')
            end;

          end;
        end;
      1:
        begin
          AddChild(NewNode, 'Copying audio');
        end;
      2:
        begin
          AddChild(NewNode, 'No audio');
        end;
    end;

  end;

  SummaryView.Items.Item[0].Selected := True;
  SummaryView.Items.Item[0].SelectedIndex := 0;

  AddToLog(0, '');
  AddToLog(0, '----Encoding Summary----');
  for I := 0 to SummaryView.Items.Count - 1 do
  begin
    Application.ProcessMessages;
    if SummaryView.Items.Item[i].HasChildren then
    begin
      if SummaryView.Items.Item[i].getFirstChild.HasChildren then
      begin
        AddToLog(0, '+' + SummaryView.Items.Item[i].Text);
      end
      else
      begin
        AddToLog(0, '    +' + SummaryView.Items.Item[i].Text);
      end;
    end
    else
    begin
      AddToLog(0, '        -' + SummaryView.Items.Item[i].Text);
    end;
  end;
  AddToLog(0, 'Temp: ' + SettingsForm.TempEdit.Text);
  AddToLog(0, 'Output: ' + DirectoryEdit.Text);
  AddToLog(0, '----Encoding Summary----');
  AddToLog(0, '');

end;

procedure TMainForm.FLACFLAC1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 6;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.FLACPercentage(const FLACOutput: string): Integer;
var
  StrPos1, StrPos2: integer;
  PercentStr: string;
begin

  if Length(FLACOutput) > 0 then
  begin
    StrPos1 := Pos(':', FLACOutput);
    StrPos2 := Pos('%', FLACOutput);

    PercentStr := Trim(Copy(FLACOutput, StrPos1 + 1, StrPos2 - StrPos1 - 1));

    if IsStringNumeric(PercentStr) then
    begin
      Result := StrToInt(PercentStr);
    end;

  end;

end;

procedure TMainForm.Force32bitBtnClick(Sender: TObject);
begin

  Set32_64Backend();

end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin

  Encoder1.Stop;
  Encoder2.Stop;
  Encoder3.Stop;
  Encoder4.Stop;
  Encoder5.Stop;
  Encoder6.Stop;
  Encoder7.Stop;
  Encoder8.Stop;

  if not UpdateThread.Terminated then
  begin
    UpdateThread.Terminate;
  end;

  while not UpdateThread.Terminated do
  begin
    Application.ProcessMessages;
    Sleep(10);
  end;

  SaveOptions();
  DeleteTempFiles();

  // save log
  // if SettingsForm.AutoLogBtn.Checked then
  // begin
  // LogForm.OutputList.Lines.SaveToFile(AppData + '\log_main.txt');
  // LogForm.EncoderOutput1.Lines.SaveToFile(AppData + '\log_encoder1.txt');
  // LogForm.EncoderOutput2.Lines.SaveToFile(AppData + '\log_encoder2.txt');
  // LogForm.EncoderOutput3.Lines.SaveToFile(AppData + '\log_encoder3.txt');
  // LogForm.EncoderOutput4.Lines.SaveToFile(AppData + '\log_encoder4.txt');
  // LogForm.EncoderOutput5.Lines.SaveToFile(AppData + '\log_encoder5.txt');
  // LogForm.EncoderOutput6.Lines.SaveToFile(AppData + '\log_encoder6.txt');
  // LogForm.EncoderOutput7.Lines.SaveToFile(AppData + '\log_encoder7.txt');
  // LogForm.EncoderOutput8.Lines.SaveToFile(AppData + '\log_encoder8.txt');
  // LogForm.DeletedLog.Lines.SaveToFile(AppData + '\log_deleted.txt');
  // end;

end;

procedure TMainForm.FormCreate(Sender: TObject);
var
  i: integer;
  SettingsFile: TIniFile;
begin

  // check necessary files.
  if not FileExists(ExtractFileDir(Application.ExeName) +
    '\tools\fhgaacenc\fhgaacenc.exe') then
  begin
    Application.MessageBox('Can''t find fhgaacenc.exe. Please re-install.',
      'Error', MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    FHGPath := ExtractFileDir(Application.ExeName) +
      '\tools\fhgaacenc\fhgaacenc.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) +
    '\tools\wavpack\wavpack.exe') then
  begin
    Application.MessageBox('Can''t find wavpack.exe. Please re-install.',
      'Error', MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    WavPackPath := ExtractFileDir(Application.ExeName) +
      '\tools\wavpack\wavpack.exe';
  end;

  NeroEncPath := ExtractFileDir(Application.ExeName) + '\neroaacenc.exe';
  NeroTagPath := ExtractFileDir(Application.ExeName) + '\neroaactag.exe';

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\ffmpeg.exe')
  then
  begin
    Application.MessageBox('Can''t find ffmpeg.exe. Please re-install.',
      'Error', MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    FFMpegPath := ExtractFileDir(Application.ExeName) + '\tools\ffmpeg.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) +
    '\tools\ttaenc\ttaenc.exe') then
  begin
    Application.MessageBox('Can''t find ttaenc.exe. Please re-install.',
      'Error', MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    TTAPath := ExtractFileDir(Application.ExeName) + '\tools\ttaenc\ttaenc.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\lyricdownloader.exe')
  then
  begin
    Application.MessageBox
      ('Can''t find lyricdownloader.exe. Please re-install.', 'Error',
      MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    LyricDownloader := ExtractFileDir(Application.ExeName) +
      '\lyricdownloader.exe';
  end;

  if IsOS64Bit then
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\lame_64.exe')
    then
    begin
      Application.MessageBox('Can''t find lame.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      LamePath := ExtractFileDir(Application.ExeName) + '\tools\lame_64.exe';
    end;
  end
  else
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\lame.exe')
    then
    begin
      Application.MessageBox('Can''t find lame.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      LamePath := ExtractFileDir(Application.ExeName) + '\tools\lame.exe';
    end;
  end;

  if IsOS64Bit then
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) +
      '\tools\WMAEncode\WMAEncode64.exe') then
    begin
      Application.MessageBox('Can''t find WMAEncode.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      WmaEncodePath := ExtractFileDir(Application.ExeName) +
        '\tools\WMAEncode\WMAEncode64.exe';
    end;
  end
  else
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) +
      '\tools\WMAEncode\WMAEncode.exe') then
    begin
      Application.MessageBox('Can''t find WMAEncode.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      WmaEncodePath := ExtractFileDir(Application.ExeName) +
        '\tools\WMAEncode\WMAEncode.exe';
    end;
  end;

  if IsOS64Bit then
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) +
      '\tools\mpc\mpcenc_64.exe') then
    begin
      Application.MessageBox('Can''t find mpcenc_64.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      MPCPath := ExtractFileDir(Application.ExeName) +
        '\tools\mpc\mpcenc_64.exe';
    end;
  end
  else
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) +
      '\tools\mpc\mpcenc.exe') then
    begin
      Application.MessageBox('Can''t find mpcenc.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      MPCPath := ExtractFileDir(Application.ExeName) + '\tools\mpc\mpcenc.exe';
    end;
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\flac.exe')
  then
  begin
    Application.MessageBox('Can''t find flac.exe. Please re-install.', 'Error',
      MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    FLACPath := ExtractFileDir(Application.ExeName) + '\tools\flac.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\MAC.exe') then
  begin
    Application.MessageBox('Can''t find MAC.exe. Please re-install.', 'Error',
      MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    MACPath := ExtractFileDir(Application.ExeName) + '\tools\MAC.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\Takc.exe')
  then
  begin
    Application.MessageBox('Can''t find Takc.exe. Please re-install.', 'Error',
      MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    TAKPath := ExtractFileDir(Application.ExeName) + '\tools\Takc.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\opusenc.exe')
  then
  begin
    Application.MessageBox('Can''t find opusenc.exe. Please re-install.',
      'Error', MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    OpusPath := ExtractFileDir(Application.ExeName) + '\tools\opusenc.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\sox\sox.exe')
  then
  begin
    Application.MessageBox('Can''t find sox.exe. Please re-install.', 'Error',
      MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    SoxPath := ExtractFileDir(Application.ExeName) + '\tools\sox\sox.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\qaac\qaac.exe')
  then
  begin
    Application.MessageBox('Can''t find qaac.exe. Please re-install.', 'Error',
      MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    QaacPath := ExtractFileDir(Application.ExeName) + '\tools\qaac\qaac.exe';
  end;

  if not FileExists(ExtractFileDir(Application.ExeName) +
    '\tools\qaac\refalac.exe') then
  begin
    Application.MessageBox('Can''t find refalac.exe. Please re-install.',
      'Error', MB_ICONERROR);
    Application.Terminate;
  end
  else
  begin
    RefAlacPath := ExtractFileDir(Application.ExeName) +
      '\tools\qaac\refalac.exe';
  end;

  if IsOS64Bit then
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) +
      '\tools\oggenc2_64.exe') then
    begin
      Application.MessageBox('Can''t find oggenc2.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      OggEncPath := ExtractFileDir(Application.ExeName) +
        '\tools\oggenc2_64.exe';
    end;
  end
  else
  begin
    if not FileExists(ExtractFileDir(Application.ExeName) + '\tools\oggenc2.exe')
    then
    begin
      Application.MessageBox('Can''t find oggenc2.exe. Please re-install.',
        'Error', MB_ICONERROR);
      Application.Terminate;
    end
    else
    begin
      OggEncPath := ExtractFileDir(Application.ExeName) + '\tools\oggenc2.exe';
    end;
  end;

  if not MediaInfoDLL_Load(ExtractFileDir(Application.ExeName) +
    '\MediaInfo.dll') then
  begin
    Application.MessageBox('Cannot load MediaInfo.dll!', 'Fatal Error',
      MB_ICONERROR);
    Application.Terminate;
  end;

  if FileExists(ExtractFileDir(Application.ExeName) + '\updater.exe') then
  begin
    if not DeleteFile(ExtractFileDir(Application.ExeName) + '\updater.exe') then
    begin
      Application.MessageBox('Can''t delete updater.exe.', 'Error',
        MB_ICONERROR);
    end;

  end;

  AppFolder := ExtractFileDir(Application.ExeName) + '\';
  if Portable then
  begin
    AppData := AppFolder;
    MyDoc := AppFolder;
  end
  else
  begin
    AppData := SystemInfo.Folders.AppData + '\TAC\';
    MyDoc := SystemInfo.Folders.Personal + '\TAC\';
  end;

  if not DirectoryExists(AppData) then
  begin
    CreateDir(AppData);
  end;

  SubtitleFiles := TStringList.Create;
  AudioIndexes := TStringList.Create;
  AudioTracks := TStringList.Create;
  CurrentFileIndexes := TStringList.Create;
  Files := TStringList.Create;
  FilesToCheck := TStringList.Create;
  Durations := TStringList.Create;
  ExtensionsForCopy := TStringList.Create;
  CopyExtension := TStringList.Create;
  Encoder1 := TEncoder.Create;
  Encoder2 := TEncoder.Create;
  Encoder3 := TEncoder.Create;
  Encoder4 := TEncoder.Create;
  Encoder5 := TEncoder.Create;
  Encoder6 := TEncoder.Create;
  Encoder7 := TEncoder.Create;
  Encoder8 := TEncoder.Create;
  CpuUsage := TJvCpuUsage.Create(nil);

  // windows 7 taskbar
  if CheckWin32Version(6, 1) then
  begin

    if not InitializeTaskbarAPI then
    begin
      Application.MessageBox
        ('You seem to have Windows 7 but TAudioConverter can''t start taskbar progressbar!',
        'Error', MB_ICONERROR);
    end;

  end;

  AudioTrackList.Items.Delimiter := '|';
  AudioTrackList.Items.StrictDelimiter := True;

  AudioEncoderIndex := 0;

end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin

  FreeAndNil(SubtitleFiles);
  FreeAndNil(AudioTracks);
  FreeAndNil(AudioIndexes);
  FreeAndNil(CurrentFileIndexes);
  FreeAndNil(Files);
  FreeAndNil(FilesToCheck);
  FreeAndNil(ExtensionsForCopy);
  FreeAndNil(Durations);
  FreeAndNil(CopyExtension);
  Encoder1.Free;
  Encoder2.Free;
  Encoder3.Free;
  Encoder4.Free;
  Encoder5.Free;
  Encoder6.Free;
  Encoder7.Free;
  Encoder8.Free;
  CpuUsage.Free;

end;

procedure TMainForm.FormShow(Sender: TObject);
var
  SettingsFile: TIniFile;
  i: integer;
  SkinIndex: integer;
begin

  // delete logs
  DeleteLogs;

  SettingsFile := TIniFile.Create(AppData + 'settings.ini');
  try

    with SettingsFile do
    begin
      SkinIndex := ReadInteger('Settings', 'Skin', 3);
      sSkinManager1.Active := not ReadBool('Settings', 'Skin2', False);
    end;
  finally
    SettingsFile.Free;

    if sSkinManager1.Active then
    begin
      sSkinManager1.SkinName := sSkinManager1.InternalSkins[SkinIndex].Name;
      SendMessage(MPCQualityBar.Handle, CM_RecreateWnd, 0, 0);
      for I := 0 to Self.ComponentCount - 1 do
      begin
        if Self.Components[i] is TJvSpinEdit then
        begin
          (Self.Components[i] as TJvSpinEdit).Color := DirectoryEdit.Color;
          (Self.Components[i] as TJvSpinEdit).Font := DirectoryEdit.Font;
        end;
      end;
    end;

  end;

  LoadOptions();
  DeleteTempFiles();

  if not DirectoryExists(GetTempDirectory) then
  begin

    if not CreateDir(GetTempDirectory) then
    begin
      Application.MessageBox('Cannot create temp folder!', 'Fatal Error',
        MB_ICONERROR);
      Application.Terminate;
    end;

  end;

  if SettingsForm.CheckUpdateBtn.Checked then
  begin
    UpdateThread.Execute(nil);
  end;

  for i := 1 to ParamCount do
  begin
    AddFile(ParamStr(i), False);
    if FileExists(ParamStr(i)) then
    begin
      LastDirectory := ExtractFileDir(ParamStr(i));
    end;
  end;
  UpdateListboxScrollBox(FileList);

end;

function TMainForm.GetArtwork(const FileName: string): string;
var
  MediaInfoHandle: Cardinal;
  ArtData: ansistring;
begin

  Result := '';

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '1');

        // get artwork
        ArtData := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
          'Cover_Data', Info_Text, Info_Name);

        if Length(ArtData) < 1 then
        begin
          ArtData := '';
        end;

        Result := ArtData;

      finally
        MediaInfo_Close(MediaInfoHandle);
      end;

    end;

  end;

end;

function TMainForm.GetDuration(Index: integer): string;
var
  MediaInfoHandle: Cardinal;
  VDuration: string;
  FileName: string;
begin

  FileName := Files[Index];

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '1');

        // get length
        VDuration := MediaInfo_Get(MediaInfoHandle, Stream_Video, 0, 'Duration',
          Info_Text, Info_Name);

        if Length(VDuration) < 1 then
        begin
          if Length(Trim(VDuration)) < 1 then
          begin
            VDuration := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
              'Duration', Info_Text, Info_Name);
          end
          else
          begin
            VDuration := '0';
          end;
        end;

        Result := FloatToStr(StrToInt64(VDuration) div 1000);

      finally
        MediaInfo_Close(MediaInfoHandle);
      end;

    end;

  end;

end;

function TMainForm.GetDurationEx(const FileName: string): integer;
var
  MediaInfoHandle: Cardinal;
  VDuration: string;
begin

  Result := 0;

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '1');

        // get length
        VDuration := MediaInfo_Get(MediaInfoHandle, Stream_Video, 0, 'Duration',
          Info_Text, Info_Name);

        if Length(VDuration) < 1 then
        begin
          if Length(Trim(VDuration)) < 1 then
          begin
            VDuration := MediaInfo_Get(MediaInfoHandle, Stream_General, 0,
              'Duration', Info_Text, Info_Name);
            if Length(VDuration) < 1 then
            begin
              VDuration := '0';
            end;
          end
          else
          begin
            VDuration := '0';
          end;
        end;

        Result := StrToInt64(VDuration) div 1000;

      finally
        MediaInfo_Close(MediaInfoHandle);
      end;

    end;

  end;

end;

function TMainForm.GetFileFolderName(const FileName: string): string;
var
  TmpStr: string;
  i: integer;
  FolderName: string;
  SlashCount: integer;
  C: Char;
begin

  Result := '';

  if FileExists(FileName) and (SettingsForm.FolderStructBtn.Checked) then
  begin

    if SettingsForm.FolderStruct2Btn.Checked then
    begin
      // just one level up
      TmpStr := ReverseString(ExcludeTrailingPathDelimiter
        (ExtractFileDir(FileName)));
      for C in TmpStr do
      begin
        if C <> '\' then
        begin
          FolderName := FolderName + C;
        end
        else
        begin
          Break;
        end;
      end;
      FolderName := ReverseString(FolderName);

    end
    else
    begin
      // delete driver char
      TmpStr := ExcludeTrailingPathDelimiter(ExtractFileDir(FileName));
      Delete(TmpStr, 1, 3);
      FolderName := TmpStr;
    end;

    if Length(FolderName) > 0 then
    begin
      if SettingsForm.FolderSuffixBtn.Checked then
      begin
        case AudioEncoderIndex of
          0:
            begin
              Result := (FolderName) + '_FFMpegAAC';
            end;
          1:
            begin
              Result := (FolderName) + '_Qaac';
            end;
          2:
            begin
              Result := (FolderName) + '_AC3';
            end;
          3:
            begin
              Result := (FolderName) + '_OggVorbis';
            end;
          4:
            begin
              Result := (FolderName) + '_Lame';
            end;
          5:
            begin
              Result := (FolderName) + '_WAV';
            end;
          6:
            begin
              Result := (FolderName) + '_FLAC';
            end;
          7:
            begin
              Result := (FolderName) + '_FHGAAC';
            end;
          8:
            begin
              Result := (FolderName) + '_Opus';
            end;
          9:
            begin
              Result := (FolderName) + '_MPC';
            end;
          10:
            begin
              Result := (FolderName) + '_APE';
            end;
          11:
            begin
              Result := (FolderName) + '_TTA';
            end;
          12:
            begin
              Result := (FolderName) + '_TAK';
            end;
          13:
            begin
              Result := (FolderName) + '_NEROAAC';
            end;
          14:
            begin
              Result := (FolderName) + '_ALAC';
            end;
          15:
            begin
              Result := (FolderName) + '_WMA';
            end;
          16:
            begin
              Result := (FolderName) + '_WavPack';
            end;
        end;

        // differen for copy
        if AudioMethodList.ItemIndex = 1 then
        begin
          Result := (FolderName) + '_COPY'
        end;
      end
      else
      begin
        Result := FolderName;
      end;

    end;
  end;

end;

procedure TMainForm.GetFullInfo(const FileName: string);
var
  MediaInfoHandle: Cardinal;
  i: Integer;
  DotPos: Integer;
  NewItem: TListItem;
  Line: string;
begin

  if (FileExists(FileName)) then
  begin

    // New handle for mediainfo
    MediaInfoHandle := MediaInfo_New();

    if MediaInfoHandle <> 0 then
    begin

      try
        // Open a file in complete mode
        MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
        MediaInfo_Option(0, 'Complete', '');

        InfoForm.InfoTMP.Text := string(MediaInfo_Inform(MediaInfoHandle, 0));

        if InfoForm.InfoTMP.Count > 0 then
        begin

          for I := 0 to InfoForm.InfoTMP.Count - 1 do
          begin
            Application.ProcessMessages;

            Line := InfoForm.InfoTMP.Strings[i];

            DotPos := Pos(':', Line);

            if DotPos > 0 then
            begin

              NewItem := InfoForm.InfoList.Items.Add;

              with NewItem do
              begin
                Caption := Copy(Line, 1, DotPos - 1);
                SubItems.Add(Copy(Line, DotPos + 1, MAXINT));
              end;

            end
            else
            begin

              if Length(Line) > 0 then
              begin
                NewItem := InfoForm.InfoList.Items.Add;

                with NewItem do
                begin
                  Caption := Line;
                  SubItems.Add('');
                end;

              end;

            end;

          end;

        end;

      finally
        MediaInfo_Close(MediaInfoHandle);
        // UpdateListboxScrollBox(InfoForm.InfoList);
      end;

    end;

  end;

end;

function TMainForm.GetPercentage(const EncoderIndex: integer): integer;
var
  Encoder: TEncoder;
begin

  case EncoderIndex of
    1:
      begin
        Encoder := Encoder1;
      end;
    2:
      begin
        Encoder := Encoder2;
      end;
    3:
      begin
        Encoder := Encoder3;
      end;
    4:
      begin
        Encoder := Encoder4;
      end;
    5:
      begin
        Encoder := Encoder5;
      end;
    6:
      begin
        Encoder := Encoder6;
      end;
    7:
      begin
        Encoder := Encoder7;
      end;
    8:
      begin
        Encoder := Encoder8;
      end;
  end;

  if Length(Encoder.ConsoleOutput) > 0 then
  begin
    if Encoder.ProcessId > 0 then
    begin
      // decide running process kind
      if Encoder.CurrentProcessType = '2' then
      begin
        // audio decoding
        Result := FFMpegPercentage(Encoder.ConsoleOutput,
          Encoder.CurrentDuration);
      end
      else if Encoder.CurrentProcessType = '8' then
      begin
        // qaac
        Result := x264Percentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '10' then
      begin
        // ogg vorbis
        Result := x264Percentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '15' then
      begin
        // sox
        Result := SoXPercentage(Encoder.ConsoleOutput)
      end
      else if Encoder.CurrentProcessType = '16' then
      begin
        // lame
        Result := LamePercentage(Encoder.ConsoleOutput)
      end
      else if Encoder.CurrentProcessType = '17' then
      begin
        // flac
        Result := FLACPercentage(Encoder.ConsoleOutput)
      end
      else if Encoder.CurrentProcessType = '18' then
      begin
        // fhg
        Result := MkvExtractPercentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '19' then
      begin
        // opus
        Result := OpusPercentage(Encoder.ConsoleOutput,
          Encoder.CurrentDuration);
      end
      else if Encoder.CurrentProcessType = '20' then
      begin
        // mpc
        Result := MPCPercentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '21' then
      begin
        // ape
        // log(Encoder.ConsoleOutput);
        Result := ApePercentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '22' then
      begin
        // tta
        Result := ApePercentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '23' then
      begin
        // tak
        Result := TAKPercentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '7' then
      begin
        // nero
        Result := NeroPercentage(Encoder.ConsoleOutput,
          Encoder.CurrentDuration);
      end
      else if Encoder.CurrentProcessType = '25' then
      begin
        // alac
        Result := x264Percentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '26' then
      begin
        // wmaencoder
        Result := WMAEncoderPercentage(Encoder.ConsoleOutput);
      end
      else if Encoder.CurrentProcessType = '28' then
      begin
        // wavpack

      end;
    end;
  end;

end;

function TMainForm.GetTempDirectory: string;
var
  SettingsFile: TIniFile;
begin

  if Portable then
  begin
    Result := SystemInfo.Folders.Temp + '\TAudioConverter\';
  end
  else
  begin
    SettingsFile := TIniFile.Create(AppData + 'settings.ini');
    try
      with SettingsFile do
      begin
        Result := ReadString('Settings', 'Temp', SystemInfo.Folders.Temp +
          '\TAudioConverter\');
      end;
    finally
      SettingsFile.Free;
    end;
  end;

end;

procedure TMainForm.InfoBtnClick(Sender: TObject);
var
  index: Integer;
begin

  index := FileList.ItemIndex;

  if index > -1 then
  begin
    GetFullInfo(Files[index]);
    InfoForm.show;
  end;

end;

function TMainForm.IntToTime(IntTime: Integer): string;
var
  hour: Integer;
  second: Integer;
  minute: Integer;
  strhour: string;
  strminute: string;
  strsecond: String;
begin

  if (Time > 0) then
  begin

    hour := IntTime div 3600;
    minute := (IntTime div 60) - (hour * 60);
    second := (IntTime mod 60);

    if (second < 10) then
    begin
      strsecond := '0' + FloatToStr(second);
    end
    else
    begin
      strsecond := FloatToStr(second);
    end;

    if (minute < 10) then
    begin
      strminute := '0' + FloatToStr(minute);
    end
    else
    begin
      strminute := FloatToStr(minute);
    end;

    if (hour < 10) then
    begin
      strhour := '0' + FloatToStr(hour);
    end
    else
    begin
      strhour := FloatToStr(hour);
    end;

    Result := strhour + ':' + strminute + ':' + strsecond;
  end
  else
  begin
    Result := '00:00:00';
  end;

end;

function TMainForm.IsAudioOnly(const FileName: string): Boolean;
var
  MediaInfoHandle: Cardinal;
  VideoCount: string;
begin

  Result := False;

  if (FileExists(FileName)) then
  begin

    // avs file exception
    if LowerCase(ExtractFileExt(FileName)) = '.avs' then
    begin
      Result := False;
    end
    else
    begin
      // New handle for mediainfo
      MediaInfoHandle := MediaInfo_New();

      if MediaInfoHandle <> 0 then
      begin

        try
          // Open a file in complete mode
          MediaInfo_Open(MediaInfoHandle, PwideChar(FileName));
          MediaInfo_Option(0, 'Complete', '1');

          VideoCount := Trim(MediaInfo_Get(MediaInfoHandle, Stream_Video, 0,
            'Count', Info_Text, Info_Name));

          if IsStringNumeric(VideoCount) then
          begin
            if StrToInt(VideoCount) > 0 then
            begin
              Result := False;
            end
            else
            begin
              Result := True;
            end;
          end
          else
          begin
            Result := True;
          end;

        finally
          MediaInfo_Close(MediaInfoHandle);
        end;

      end;

    end;

  end;

end;

function TMainForm.IsOS64Bit: Boolean;
type
  TIsWow64Process = function(Handle: THandle; var IsWow64: BOOL): BOOL; stdcall;
var
  hKernel32: Integer;
  IsWow64Process: TIsWow64Process;
  IsWow64: BOOL;
begin
  // that function is copied from: http://stackoverflow.com/questions/601089/detect-whether-current-windows-version-is-32-bit-or-64-bit

  // we can check if the operating system is 64-bit by checking whether
  // we are running under Wow64 (we are 32-bit code). We must check if this
  // function is implemented before we call it, because some older versions
  // of kernel32.dll (eg. Windows 2000) don't know about it.
  // see http://msdn.microsoft.com/en-us/library/ms684139%28VS.85%29.aspx

  Result := False;
  hKernel32 := LoadLibrary('kernel32.dll');
  if (hKernel32 = 0) then
    RaiseLastOSError;
  @IsWow64Process := GetProcAddress(hKernel32, 'IsWow64Process');
  if Assigned(IsWow64Process) then
  begin
    IsWow64 := False;
    if (IsWow64Process(GetCurrentProcess, IsWow64)) then
    begin
      Result := IsWow64;
    end
    else
      RaiseLastOSError;
  end;
  FreeLibrary(hKernel32);

end;

function TMainForm.IsStringNumeric(Str: string): Boolean;
var
  p: PChar;
begin

  if Length(Str) < 1 then
  begin
    Result := False;
    Exit;
  end;

  p := PChar(Str);
  Result := False;

  while p^ <> #0 do
  begin
    Application.ProcessMessages;

    if (Not CharInSet(p^, ['0' .. '9'])) then
    begin
      Exit;
    end;

    Inc(p);
  end;

  Result := True;
end;

procedure TMainForm.LameEncodeListChange(Sender: TObject);
begin

  if LameEncodeList.ItemIndex = 2 then
  begin
    LameVBREdit.Enabled := True;
    LameBitrateEdit.Enabled := False;
  end
  else
  begin
    LameVBREdit.Enabled := False;
    LameBitrateEdit.Enabled := True;
  end;

end;

procedure TMainForm.LameMP31Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 4;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.LamePercentage(const LameOutput: string): Integer;
var
  pos1: Integer;
  pos2: Integer;
  prog: String;
  Tmp: string;
begin

  if (Length(LameOutput) > 0) then
  begin
    Tmp := LameOutput;

    pos1 := Pos('(', Trim(Tmp));
    pos2 := Pos('%', Trim(Tmp));
    prog := Trim(Copy(Tmp, pos1 + 1, (pos2 - pos1 - 1)));

    if IsStringNumeric(prog) then
    begin
      Result := StrToInt(prog);
    end;

  end;

end;

procedure TMainForm.LaunchProcesses(const ProcessCount: integer);
begin

  case ProcessCount of
    1:
      begin
        Encoder1.Start;
      end;
    2:
      begin
        Encoder1.Start;
        Encoder2.Start;
      end;
    3:
      begin
        Encoder1.Start;
        Encoder2.Start;
        Encoder3.Start;
      end;
    4:
      begin
        Encoder1.Start;
        Encoder2.Start;
        Encoder3.Start;
        Encoder4.Start;
      end;
    5:
      begin
        Encoder1.Start;
        Encoder2.Start;
        Encoder3.Start;
        Encoder4.Start;
        Encoder5.Start;
      end;
    6:
      begin
        Encoder1.Start;
        Encoder2.Start;
        Encoder3.Start;
        Encoder4.Start;
        Encoder5.Start;
        Encoder6.Start;
      end;
    7:
      begin
        Encoder1.Start;
        Encoder2.Start;
        Encoder3.Start;
        Encoder4.Start;
        Encoder5.Start;
        Encoder6.Start;
        Encoder7.Start;
      end;
    8:
      begin
        Encoder1.Start;
        Encoder2.Start;
        Encoder3.Start;
        Encoder4.Start;
        Encoder5.Start;
        Encoder6.Start;
        Encoder7.Start;
        Encoder8.Start;
      end;
  end;

end;

procedure TMainForm.LoadOptions;
var
  SettingsFile: TIniFile;
  SkinIndex, i: integer;
begin

  SettingsFile := TIniFile.Create(AppData + 'settings.ini');
  try

    with SettingsFile do
    begin
      DirectoryEdit.Text := ReadString('Settings', 'OutDir', MyDoc);

      AudioEncoderIndex := ReadInteger('Settings', 'AudioPage', 4);

      FAACBitrateEdit.Text := ReadString('Settings', 'FAACBitrate', '128');

      QaacEncodeMethodList.ItemIndex := ReadInteger('Settings',
        'QaacEncode', 0);
      QaacvQualityEdit.Text := ReadString('Settings', 'QaacQuality', '64');
      QaacBitrateEdit.Text := ReadString('Settings', 'QaacBitrate', '128');
      QaacQualityList.ItemIndex := ReadInteger('Settings', 'QaacProfile', 2);
      QaacHEBtn.Checked := ReadBool('Settings', 'QaacHE', False);

      AudioMethodList.ItemIndex := ReadInteger('Settings', 'AudioMethod', 0);

      OggencodeList.ItemIndex := ReadInteger('Settings', 'OggEncode', 0);
      OggQualityEdit.Text := ReadString('Settings', 'OggQuality', '6');
      OggBitrateEdit.Text := ReadString('Settings', 'OggBitrate', '128');
      OggManagedBitrateBtn.Checked := ReadBool('Settings', 'OggManaged', False);

      LameEncodeList.ItemIndex := ReadInteger('Settings', 'LAmeEncode', 0);
      LameVBREdit.Text := ReadString('Settings', 'LameVBR', '2');
      LameBitrateEdit.Text := ReadString('Settings', 'LameBit', '128');
      LameQualityEdit.Text := ReadString('Settings', 'LameQ', '3');
      LameTagList.ItemIndex := ReadInteger('Settings', 'LameTag', 0);

      AftenEncodeList.ItemIndex := ReadInteger('Settings', 'AftenEncode', 0);
      AftenQualityEdit.Text := ReadString('Settings', 'AftenQuality', '240');
      AftenBitrateEdit.Text := ReadString('Settings', 'AftenBitrate', '320');

      FHGMethodList.ItemIndex := ReadInteger('Settings', 'FHGEncode', 0);
      FHGQualityEdit.Text := ReadString('Settings', 'FHGQuality', '6');
      FHGBitrateEdit.Text := ReadString('Settings', 'FHGBitrate', '128');
      FHGProfileList.ItemIndex := ReadInteger('Settings', 'FHGProfile', 0);

      OpusEncodeMethodList.ItemIndex := ReadInteger('Settings', 'OpusEnc', 0);
      OpusBitrateEdit.Text := ReadString('Settings', 'OpusBitrate', '128');
      OpusCompEdit.Text := ReadString('Settings', 'OpusQuality', '8');

      NeroMethodList.ItemIndex := ReadInteger('Settings', 'NeroEncode', 0);
      NeroQualityEdit.Text := ReadString('Settings', 'NeroQuality',
        FloatToStr(NeroQualityEdit.MaxValue / 2));
      NeroBitrateEdit.Text := ReadString('Settings', 'NeroBitrate', '128');
      NeroProfileList.ItemIndex := ReadInteger('Settings', 'NeroProfile', 0);

      MACLevelList.ItemIndex := ReadInteger('Settings', 'MAC', 1);
      MPCQualityBar.Position := ReadInteger('Settings', 'MPC', 500);

      WavPackMethodList.ItemIndex := ReadInteger('Settings', 'WPMethod', 0);
      WavPackBitrateEdit.Text := ReadString('settings', 'WPBitrate', '256');
      WavPackExtraBtn.Checked := ReadBool('Settings', 'WPExtra', True);
      WavPackCorrectionBtn.Checked := ReadBool('Settings', 'WPCorrect', True);

      SameAsSourceBtn.Checked := ReadBool('Settings', 'SameAsSource', False);

      LastDirectory := ReadString('Settings', 'LastDir',
        SystemInfo.Folders.Personal);

      PostEncodeList.ItemIndex := ReadInteger('Settings', 'Post', 0);

      FLACCompList.ItemIndex := ReadInteger('Settings', 'FlacComp', 5);
      FLACEMSBtn.Checked := ReadBool('Settings', 'FlacEMS', False);

      BitDepthList.ItemIndex := ReadInteger('Settings', 'Depth', 0);

      SkinIndex := ReadInteger('Settings', 'Skin', 3);

      WMAMethodList.ItemIndex := ReadInteger('Settings', 'WMAMethod', 1);
      WMACodecList.ItemIndex := ReadInteger('Settings', 'WMACodec', 0);
      WMAQualityList.ItemIndex := ReadInteger('Settings', 'WMAQaulity', 3);
      WMABitrateEdit.Text := ReadString('Settings', 'WMABitrate', '128');
    end;

  finally
    SettingsFile.Free;

    QaacEncodeMethodList.OnChange(Self);
    OggencodeList.OnChange(Self);
    AftenEncodeList.OnChange(Self);
    AudioMethodList.OnChange(Self);
    LameEncodeList.OnChange(Self);
    SameAsSourceBtn.OnClick(Self);
    FHGMethodList.OnChange(Self);
    MPCQualityBar.OnChange(Self);
    NeroMethodList.OnChange(Self);
    WMAMethodList.OnChange(Self);
    WavPackMethodList.OnChange(Self);

    SetPanelState(AudioEncoderIndex);
    case AudioEncoderIndex of
      0:
        AudioCodecBtn.Caption := 'AAC (FAAC)';
      1:
        AudioCodecBtn.Caption := 'AAC (QAAC)';
      2:
        AudioCodecBtn.Caption := 'AC3 (FFMpeg)';
      3:
        AudioCodecBtn.Caption := 'OGG (Ogg Vorbis)';
      4:
        AudioCodecBtn.Caption := 'MP3 (Lame)';
      5:
        AudioCodecBtn.Caption := 'WAV (FFMpeg)';
      6:
        AudioCodecBtn.Caption := 'FLAC (FLAC)';
      7:
        AudioCodecBtn.Caption := 'AAC (Fhgaacenc)';
      8:
        AudioCodecBtn.Caption := 'Opus (OpusEnc)';
      9:
        AudioCodecBtn.Caption := 'MPC (MPCEnc)';
      10:
        AudioCodecBtn.Caption := 'Monkey''s Audio (MAC)';
      11:
        AudioCodecBtn.Caption := 'TTA (TTAEnc)';
      12:
        AudioCodecBtn.Caption := 'TAK (TAKc)';
      13:
        AudioCodecBtn.Caption := 'AAC (NeroAACEnc)';
      14:
        AudioCodecBtn.Caption := 'ALAC (REFALAC)';
      15:
        AudioCodecBtn.Caption := 'WMA (WMAEncode)';
      16:
        AudioCodecBtn.Caption := 'WavPack';
    end;

    SameAsSourceBtn.OnClick(Self);

    sSkinManager1.SkinName := sSkinManager1.InternalSkins[SkinIndex].Name;
    SendMessage(MPCQualityBar.Handle, CM_RecreateWnd, 0, 0);
    for I := 0 to Self.ComponentCount - 1 do
    begin
      if Self.Components[i] is TJvSpinEdit then
      begin
        (Self.Components[i] as TJvSpinEdit).Color := DirectoryEdit.Color;
        (Self.Components[i] as TJvSpinEdit).Font := DirectoryEdit.Font;
      end;
    end;

  end;

end;

procedure TMainForm.Log(const MSG: string);
begin
  LogForm.OutputList.Lines.Add(MSG);
end;

procedure TMainForm.LogsBtnClick(Sender: TObject);
begin

  LogForm.show;

end;

function TMainForm.MkvExtractPercentage(const MkvExtractOutput: string)
  : Integer;
var
  TmpInt: Integer;
  FConsoleOutput: string;
begin

  FConsoleOutput := Trim(MkvExtractOutput);

  if Length(FConsoleOutput) > 0 then
  begin

    if Copy(FConsoleOutput, 0, 9) = 'Progress:' then
    begin
      FConsoleOutput := Trim(ReplaceStr(FConsoleOutput, '%', ''));
      FConsoleOutput := Trim(Copy(FConsoleOutput, 10, MAXINT));

      if TryStrToInt(FConsoleOutput, TmpInt) then
      begin
        Result := TmpInt;
      end;

    end;

  end;

end;

procedure TMainForm.MonkeysAudioAPE1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 10;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.MPCEncMPC1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 9;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.MPCPercentage(const MPCOutput: string): integer;
var
  PercentStr: string;
begin

  if Length(MPCOutput) > 0 then
  begin

    PercentStr := Trim(Copy(MPCOutput, 1, 3));
    if IsStringNumeric(PercentStr) then
    begin
      if PercentStr = '100' then
      begin
        Result := 100;
      end;
    end
    else
    begin
      PercentStr := Trim(Copy(MPCOutput, 1, 2));
      if IsStringNumeric(PercentStr) then
      begin
        Result := StrToInt(PercentStr);
      end;
    end;

  end;

end;

procedure TMainForm.MPCQualityBarChange(Sender: TObject);
var
  ValueStr: string;
begin

  if MPCQualityBar.Position < 10 then
  begin
    ValueStr := FloatToStr(MPCQualityBar.Position);
    Insert('.0', ValueStr, Length(FloatToStr(MPCQualityBar.Position)) - 1);
    MPCQualityEdit.Text := '0' + ValueStr;
  end
  else if MPCQualityBar.Position < 100 then
  begin
    ValueStr := FloatToStr(MPCQualityBar.Position);
    Insert('.', ValueStr, Length(FloatToStr(MPCQualityBar.Position)) - 1);
    MPCQualityEdit.Text := '0' + ValueStr;
  end
  else
  begin
    ValueStr := FloatToStr(MPCQualityBar.Position);
    Insert('.', ValueStr, Length(FloatToStr(MPCQualityBar.Position)) - 1);
    MPCQualityEdit.Text := ValueStr;
  end;

end;

procedure TMainForm.MplayerProcessTerminate(Sender: TObject;
  ExitCode: Cardinal);
begin

  // with LogForm.MplayerOutputList.Items do
  // begin
  // Add('[' + DateToStr(Now) + ']');
  // Add('MPlayer command line: ' + MplayerProcess.CommandLine);
  // AddStrings(MplayerProcess.ConsoleOutput);
  // Add('');
  // end;
  //
  // UpdateListboxScrollBox(LogForm.MplayerOutputList);

end;

procedure TMainForm.NeroAACEncAAC1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 13;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.NeroMethodListChange(Sender: TObject);
begin

  NeroBitrateEdit.Enabled := NeroMethodList.ItemIndex <> 0;
  NeroQualityEdit.Enabled := NeroMethodList.ItemIndex = 0;

end;

function TMainForm.NeroPercentage(const NeroOutput: string;
  const DurationStr: string): integer;
var
  FConsoleOutput: string;
begin

  Result := 0;

  FConsoleOutput := Trim(NeroOutput);

  if Length(FConsoleOutput) > 0 then
  begin

    FConsoleOutput := Trim(ReplaceStr(FConsoleOutput, 'Processed', ''));
    FConsoleOutput := Trim(ReplaceStr(FConsoleOutput, 'seconds...', ''));
    FConsoleOutput := Trim(FConsoleOutput);
    // form1.Caption := FloatToStr(DurationIndex);
    if IsStringNumeric(FConsoleOutput) then
    begin
      if (StrToInt(Durations[DurationIndex]) > 0) then
      begin
        Result := (100 * StrToInt(FConsoleOutput)) div StrToInt(DurationStr);
      end;
    end

  end;

end;

procedure TMainForm.OggencodeListChange(Sender: TObject);
begin

  if OggencodeList.ItemIndex = 0 then
  begin
    OggQualityEdit.Enabled := True;
    OggBitrateEdit.Enabled := False;
    OggManagedBitrateBtn.Enabled := False;
  end
  else
  begin
    OggQualityEdit.Enabled := False;
    OggBitrateEdit.Enabled := True;
    OggManagedBitrateBtn.Enabled := True;
  end;

end;

procedure TMainForm.OggVorbisOgg1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 3;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.OpenDirectory1Click(Sender: TObject);
var
  FileDir: string;
  index: Integer;
begin

  index := FileList.ItemIndex;

  if index > -1 then
  begin
    FileDir := ExtractFileDir(Files[index]);

    if DirectoryExists(FileDir) then
    begin

      ShellExecute(Handle, 'open', 'explorer',
        PChar(' /n,/select, ' + '"' + Files[index] + '"'), nil, SW_SHOWNORMAL);

    end;

  end;

end;

procedure TMainForm.OpusOpus1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 8;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.OpusPercentage(const OpusOutput: string;
  const DurationStr: string): integer;
var
  StrPos1, StrPos2: integer;
  PercentStr: string;
  PositionInt: integer;
begin

  if Length(OpusOutput) > 0 then
  begin
    StrPos1 := Pos(']', OpusOutput);
    StrPos2 := Pos('.', OpusOutput);

    PercentStr := Trim(Copy(OpusOutput, StrPos1 + 1, StrPos2 - StrPos1 - 1));
    PercentStr := IntToStr(TimeToInt(PercentStr));
    PositionInt := StrToInt(PercentStr);

    if IsStringNumeric(DurationStr) then
    begin
      if (StrToInt(DurationStr) > 0) then
      begin
        Result := (100 * PositionInt) div StrToInt(DurationStr);
      end;
    end;

  end;

end;

procedure TMainForm.OutputBtnClick(Sender: TObject);
begin

  if (DirectoryExists(DirectoryEdit.Text)) then
  begin
    ShellExecute(Application.Handle, 'open', PChar(DirectoryEdit.Text), nil,
      nil, SW_SHOWNORMAL);
  end
  else
  begin
    Application.MessageBox
      ('Cannot open output folder because it does not exist!', 'Error',
      MB_ICONERROR);
  end;

end;

procedure TMainForm.Play1Click(Sender: TObject);
var
  index: Integer;
begin

  index := FileList.ItemIndex;

  if index > -1 then
  begin
    ShellExecute(Application.Handle, 'open', PChar(Files[index]), nil, nil,
      SW_SHOWNORMAL);
  end;

end;

procedure TMainForm.PositionTimerTimer(Sender: TObject);
var
  TotalProgress: integer;
  AllDone: Boolean;
  EncodingSpeed: Extended;
begin

  TotalProgress := UpdateProgressUI;

  MainForm.Caption := FloatToStr(TotalProgressBar.PercentDone) +
    '% [TAudioConverter]';

  SetProgressValue(Self.Handle, TotalProgressBar.Progress,
    TotalProgressBar.MaxValue);

  if not SettingsForm.CPUBtn.Checked then
  begin
    CPUBar.Progress := Round(CpuUsage.Usage);
    MemoryBar.Progress :=
      (100 * (SystemInfo.Memory.TotalPhysicalMemory -
      SystemInfo.Memory.FreePhysicalMemory))
      div SystemInfo.Memory.TotalPhysicalMemory;
  end
  else
  begin
    CPUBar.Progress := 0;
    MemoryBar.Progress := 0;
  end;

  // done all
  AllDone := False;
  if AudioEncoderIndex = 5 then
  begin
    AllDone := TotalProgress = FileList.Items.Count
  end
  else
  begin
    AllDone := TotalProgress = TotalCMDCount;
  end;

  if AllDone then
  begin
    PositionTimer.Enabled := False;

    Self.Caption := 'TAudioConverter';

    TotalProgressBar.Progress := 0;
    SetProgressValue(Self.Handle, 0, 100);
    SetProgressState(Self.Handle, tbpsNone);
    Timer.Enabled := False;
    TimePassedLabel.Caption := 'Time Passed: 00:00:00';

    SaveLogs;
    EnableUI;
    if sSkinManager1.Active then
    begin
      sSkinManager1.RepaintForms(True);
    end;

    // post-encode action
    case PostEncodeList.ItemIndex of
      0:
        begin

          // checks if all the output files created
          if CheckOutputFiles then
          begin
            // calculate encoding speed
            EncodingSpeed := 0;
            if TimePassed <= 0 then
            begin
              TimePassed := 1;
            end;
            EncodingSpeed := TotalLength / TimePassed;

            TrayIcon.Active := True;
            TrayIcon.BalloonHint('TAudioConverter',
              'TAudioConverter converted files with speed of x' +
              FormatFloat('#,##', EncodingSpeed) + ' (Converted ' +
              IntToTime(TotalLength) + ' in ' + IntToTime(TimePassed) + ').',
              btInfo, 5000);

            AddToLog(0, 'TAudioConverter converted files with speed x' +
              FormatFloat('#,##', EncodingSpeed) + ' (Converted ' +
              IntToTime(TotalLength) + ' in ' + IntToTime(TimePassed) + ').');
            if sSkinManager1.Active then
            begin
              sSkinManager1.RepaintForms(True);
            end;
          end
          else
          begin

          end;

        end;
      1:
        begin
          Application.Terminate;
        end;
      2:
        begin
          if not SameAsSourceBtn.Checked then
          begin
            if (DirectoryExists(DirectoryEdit.Text)) then
            begin
              ShellExecute(Application.Handle, 'open',
                PChar(DirectoryEdit.Text), nil, nil, SW_SHOWNORMAL);
            end
            else
            begin
              Application.MessageBox
                ('Cannot open output folder because it does not exist!',
                'Error', MB_ICONERROR);
            end;
          end;
        end;
      3:
        begin
          ShutDown(EWX_SHUTDOWN or EWX_FORCE or EWX_FORCEIFHUNG);
        end;
      4:
        begin
          ShutDown(EWX_REBOOT or EWX_FORCE or EWX_FORCEIFHUNG);
        end;
      5:
        begin
          ShutDown(EWX_LOGOFF or EWX_FORCE or EWX_FORCEIFHUNG);
        end;
    end;

    TimePassed := 0;
  end;

end;

procedure TMainForm.PostEncodeListChange(Sender: TObject);
begin

  SettingsForm.PostEncode2List.ItemIndex := PostEncodeList.ItemIndex;

end;

procedure TMainForm.REFALACALAC1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 14;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.RemoveAllBtnClick(Sender: TObject);
begin

  if FileList.Items.Count < 1 then
    Exit;

  if ID_YES = Application.MessageBox('Remove all from list?', 'Remove All',
    MB_ICONQUESTION or MB_YESNO) then
  begin
    FileList.Items.Clear;
    AudioTracks.Clear;
    AudioIndexes.Clear;
    AudioTrackList.Items.Clear;
    DirecortyLabel.Caption := '';
    Files.Clear;
    Durations.Clear;
    ExtensionsForCopy.Clear;
    CopyExtension.Clear;
    FileList.Hint := '0 file(s)';
  end;

end;

procedure TMainForm.RemoveBtnClick(Sender: TObject);
var
  i: Integer;
begin

  FileList.Items.BeginUpdate;
  try
    for I := FileList.Items.Count - 1 downto 0 do
    begin
      Application.ProcessMessages;

      if FileList.Selected[i] then
      begin
        FileList.Items.Delete(i);
        AudioTracks.Delete(i);
        AudioIndexes.Delete(i);
        Files.Delete(i);
        Durations.Delete(i);
        ExtensionsForCopy.Delete(i);
        CopyExtension.Delete(i);
      end;

    end;

  finally
    FileList.Items.EndUpdate;
    FileList.OnClick(Self);
    FileList.Hint := FloatToStr(FileList.Items.Count) + ' file(s)';
    UpdateListboxScrollBox(FileList);
  end;

end;

function TMainForm.RemoveNonDigits(const InputStr: string): string;
var
  C: Char;
  TmpStr: string;
begin

  Result := InputStr;
  for C in InputStr do
  begin
    Application.ProcessMessages;
    if CharInSet(C, ['0' .. '9']) then
    begin
      TmpStr := TmpStr + C;
    end;
  end;

  if Length(TmpStr) > 0 then
  begin
    Result := TmpStr;
  end;

end;

function TMainForm.RemoveQuotation(const Source: string): string;
var
  Tmp: string;
  C: Char;
begin

  Result := Source;

  for C in Source do
  begin
    if C <> '"' then
    begin
      Tmp := Tmp + C;
    end;
  end;

  if Length(Tmp) > 0 then
  begin
    Result := Tmp;
  end;

end;

procedure TMainForm.SameAsSourceBtnClick(Sender: TObject);
begin

  DirectoryEdit.Enabled := not SameAsSourceBtn.Checked;

end;

procedure TMainForm.SaveArtwork(const ArtworkData: ansistring;
  const OutputFolder: string; const FileName: string);
Const
  JPEG = '/9j/';
  PNG = 'iVBOR';
var
  OutputFileName: string;
  ImageStream: TBytesStream;
begin

  if DirectoryExists(OutputFolder) then
  begin

    ImageStream := TBytesStream.Create(DecodeBase64(ArtworkData));
    try

      if Copy(ArtworkData, 1, Length(JPEG)) = JPEG then
      begin
        if SettingsForm.ArtworkSuffixBtn.Checked then
        begin
          OutputFileName := OutputFolder + '\' + FileName + '.jpg';
        end
        else
        begin
          OutputFileName := OutputFolder + '\folder.jpg';
        end;
      end
      else if Copy(ArtworkData, 1, Length(PNG)) = PNG then
      begin
        if SettingsForm.ArtworkSuffixBtn.Checked then
        begin
          OutputFileName := OutputFolder + '\' + FileName + '.png';
        end
        else
        begin
          OutputFileName := OutputFolder + '\folder.png';
        end;;
      end;

      if Length(OutputFileName) > 0 then
      begin
        ImageStream.SaveToFile(OutputFileName);
      end;

    finally
      ImageStream.Free;
    end;

  end;

end;

function TMainForm.SaveArtwork2(const ArtworkData: ansistring;
  const OutputFolder: string; const FileName: string): string;
Const
  JPEG = '/9j/';
  PNG = 'iVBOR';
var
  OutputFileName: string;
  ImageStream: TBytesStream;
begin

  Result := '';
  if DirectoryExists(OutputFolder) then
  begin

    ImageStream := TBytesStream.Create(DecodeBase64(ArtworkData));
    try

      if Copy(ArtworkData, 1, Length(JPEG)) = JPEG then
      begin
        OutputFileName := OutputFolder + '\' + FileName + '.jpg';
      end
      else if Copy(ArtworkData, 1, Length(PNG)) = PNG then
      begin
        OutputFileName := OutputFolder + '\' + FileName + '.png';
      end;

      if Length(OutputFileName) > 0 then
      begin
        ImageStream.SaveToFile(OutputFileName);
        Result := OutputFileName;
      end;

    finally
      ImageStream.Free;
    end;

  end;

end;

procedure TMainForm.SaveExternalArtwork(const FileDir, OutputFolder: string);
var
  Search: TSearchRec;
  FileName: String;
  Extension: String;
begin

  if DirectoryExists(FileDir) then
  begin
    SetCurrentDir(FileDir);

    if (FindFirst('*.*', faAnyFile, Search) = 0) then
    Begin
      repeat
        Application.ProcessMessages;

        FileName := GetCurrentDir + '\' + Search.Name;
        Extension := LowerCase(ExtractFileExt(FileName));

        if (Extension = '.jpeg') or (Extension = '.jpg') or (Extension = '.png')
        then
        begin
          if ContainsText(UpperCase(FileName), 'FRONT') or
            ContainsText(UpperCase(FileName), 'BACK') or
            ContainsText(UpperCase(FileName), 'DISC') or
            ContainsText(UpperCase(FileName), 'CD') or
            ContainsText(UpperCase(FileName), 'INLAY') or
            ContainsText(UpperCase(FileName), 'CASE') or
            ContainsText(UpperCase(FileName), 'BOX') or
            ContainsText(UpperCase(FileName), 'TRAY') or
            ContainsText(UpperCase(FileName), 'FOLDER') then
          begin
            CopyFile(PChar(FileName),
              PChar(OutputFolder + '\' + ExtractFileName(FileName)), True);
          end;
        end;

      until (FindNext(Search) <> 0) and (not AddingStopped);
      FindClose(Search);
    end;

  end;

end;

procedure TMainForm.SaveLogs;
var
  i: integer;
  TmpLst: TStringList;
begin

  Self.Enabled := False;
  ProgressForm.CurrentFileLabel.Caption := 'Creating logs please wait...';
  ProgressForm.AbortBtn.Enabled := False;
  ProgressForm.show;
  ProgressForm.BringToFront;
  TmpLst := TStringList.Create;
  try
    if not Assigned(LogForm) then
    begin
      Exit;
    end;

    with LogForm do
    begin

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder1.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(1, '');
        AddToLog(1, 'Encoder 1 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(1, TmpLst[i]);
        end;
        AddToLog(1, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder2.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(2, '');
        AddToLog(2, 'Encoder 2 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(2, TmpLst[i]);
        end;
        AddToLog(2, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder3.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(3, '');
        AddToLog(3, 'Encoder3 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(3, TmpLst[i]);
        end;
        AddToLog(3, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder4.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(4, '');
        AddToLog(4, 'Encoder4 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(4, TmpLst[i]);
        end;
        AddToLog(4, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder5.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(5, '');
        AddToLog(5, 'Encoder5 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(5, TmpLst[i]);
        end;
        AddToLog(5, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder6.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(6, '');
        AddToLog(6, 'Encoder6 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(6, TmpLst[i]);
        end;
        AddToLog(6, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder7.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(7, '');
        AddToLog(7, 'Encoder7 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(7, TmpLst[i]);
        end;
        AddToLog(7, '');
      end;

      TmpLst.Clear;
      TmpLst.AddStrings(Encoder8.GetConsoleOutput);
      if TmpLst.Count > 0 then
      begin
        AddToLog(8, '');
        AddToLog(8, 'Encoder8 Output:');
        for I := 0 to TmpLst.Count - 1 do
        begin
          Application.ProcessMessages;
          AddToLog(8, TmpLst[i]);
        end;
        AddToLog(8, '');
      end;

    end;
  finally
    ProgressForm.AbortBtn.Enabled := True;
    ProgressForm.Close;
    Self.Enabled := True;
    Self.BringToFront;
    FreeAndNil(TmpLst);
  end;

end;

procedure TMainForm.SaveOptions;
var
  SettingsFile: TIniFile;
begin

  SettingsFile := TIniFile.Create(AppData + 'settings.ini');
  try

    with SettingsFile do
    begin
      WriteString('Settings', 'OutDir', DirectoryEdit.Text);

      WriteInteger('Settings', 'AudioPage', AudioEncoderIndex);

      WriteString('Settings', 'FAACBitrate', FAACBitrateEdit.Text);

      WriteInteger('Settings', 'QaacEncode', QaacEncodeMethodList.ItemIndex);
      WriteString('Settings', 'QaacQuality', QaacvQualityEdit.Text);
      WriteString('Settings', 'QaacBitrate', QaacBitrateEdit.Text);
      WriteInteger('Settings', 'QaacProfile', QaacQualityList.ItemIndex);
      WriteBool('Settings', 'QaacHE', QaacHEBtn.Checked);

      WriteInteger('Settings', 'OggEncode', OggencodeList.ItemIndex);
      WriteString('Settings', 'OggQuality', OggQualityEdit.Text);
      WriteString('Settings', 'OggBitrate', OggBitrateEdit.Text);
      WriteBool('Settings', 'OggManaged', OggManagedBitrateBtn.Checked);

      WriteInteger('Settings', 'LAmeEncode', LameEncodeList.ItemIndex);
      WriteString('Settings', 'LameVBR', LameVBREdit.Text);
      WriteString('Settings', 'LameBit', LameBitrateEdit.Text);
      WriteString('Settings', 'LameQ', LameQualityEdit.Text);
      WriteInteger('Settings', 'LameTag', LameTagList.ItemIndex);

      WriteInteger('Settings', 'AftenEncode', AftenEncodeList.ItemIndex);
      WriteString('Settings', 'AftenQuality', AftenQualityEdit.Text);
      WriteString('Settings', 'AftenBitrate', AftenBitrateEdit.Text);

      WriteInteger('Settings', 'FHGEncode', FHGMethodList.ItemIndex);
      WriteString('Settings', 'FHGQuality', FHGQualityEdit.Text);
      WriteString('Settings', 'FHGBitrate', FHGBitrateEdit.Text);
      WriteInteger('Settings', 'FHGProfile', FHGProfileList.ItemIndex);

      WriteInteger('Settings', 'OpusEnc', OpusEncodeMethodList.ItemIndex);
      WriteString('Settings', 'OpusBitrate', OpusBitrateEdit.Text);
      WriteString('Settings', 'OpusQuality', OpusCompEdit.Text);

      WriteInteger('Settings', 'NeroEncode', NeroMethodList.ItemIndex);
      WriteString('Settings', 'NeroQuality', NeroQualityEdit.Text);
      WriteString('Settings', 'NeroBitrate', NeroBitrateEdit.Text);
      WriteInteger('Settings', 'NeroProfile', NeroProfileList.ItemIndex);

      WriteInteger('Settings', 'MAC', MACLevelList.ItemIndex);
      WriteInteger('Settings', 'MPC', MPCQualityBar.Position);

      WriteInteger('Settings', 'WPMethod', WavPackMethodList.ItemIndex);
      WriteString('settings', 'WPBitrate', WavPackBitrateEdit.Text);
      WriteBool('Settings', 'WPExtra', WavPackExtraBtn.Checked);
      WriteBool('Settings', 'WPCorrect', WavPackCorrectionBtn.Checked);

      WriteInteger('Settings', 'AudioMethod', AudioMethodList.ItemIndex);

      WriteBool('Settings', 'SameAsSource', SameAsSourceBtn.Checked);

      WriteString('Settings', 'LastDir', LastDirectory);

      WriteInteger('Settings', 'Post', PostEncodeList.ItemIndex);

      WriteInteger('Settings', 'FlacComp', FLACCompList.ItemIndex);
      WriteBool('Settings', 'FlacEMS', FLACEMSBtn.Checked);

      WriteInteger('Settings', 'Depth', BitDepthList.ItemIndex);

      WriteInteger('Settings', 'WMAMethod', WMAMethodList.ItemIndex);
      WriteInteger('Settings', 'WMACodec', WMACodecList.ItemIndex);
      WriteInteger('Settings', 'WMAQaulity', WMAQualityList.ItemIndex);
      WriteString('Settings', 'WMABitrate', WMABitrateEdit.Text);
    end;

  finally
    SettingsFile.Free;
  end;

end;

procedure TMainForm.sBitBtn1Click(Sender: TObject);
begin

  ShellExecute(Self.Handle, 'open',
    'http://www.nero.com/eng/downloads-nerodigital-nero-aac-codec.php', nil,
    nil, SW_NORMAL);

end;

procedure TMainForm.WavPackMethodListChange(Sender: TObject);
begin

  WavPackBitrateEdit.Enabled := WavPackMethodList.ItemIndex = 1;
  WavPackCorrectionBtn.Enabled := WavPackBitrateEdit.Enabled;

end;

procedure TMainForm.WavPackVW1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 16;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.WikiBtnClick(Sender: TObject);
begin
  ShellExecute(0, 'open', 'http://en.wikipedia.org/wiki/Audio_bit_depth', nil,
    nil, SW_SHOWNORMAL);
end;

procedure TMainForm.SeeLogtxt1Click(Sender: TObject);
begin

  SettingsForm.SeeLogBtn.OnClick(Self);

end;

procedure TMainForm.SelectDirBtnClick(Sender: TObject);
begin

  if DirectoryExists(DirectoryEdit.Text) then
  begin
    OpenFolderDialog.Directory := DirectoryEdit.Text;
  end;

  if OpenFolderDialog.Execute then
  begin
    DirectoryEdit.Text := OpenFolderDialog.Directory;
  end;

end;

procedure TMainForm.Set32_64Backend;
begin

  if IsOS64Bit then
  begin
    FFMpegPath := ExtractFileDir(Application.ExeName) + '\tools\ffmpeg_64.exe';
  end
  else
  begin
    FFMpegPath := ExtractFileDir(Application.ExeName) + '\tools\ffmpeg.exe';
  end;

  if IsOS64Bit then
  begin
    LamePath := ExtractFileDir(Application.ExeName) + '\tools\lame_64.exe';
  end
  else
  begin
    LamePath := ExtractFileDir(Application.ExeName) + '\tools\lame.exe';
  end;

  if IsOS64Bit then
  begin
    OggEncPath := ExtractFileDir(Application.ExeName) + '\tools\oggenc2_64.exe';
  end
  else
  begin
    OggEncPath := ExtractFileDir(Application.ExeName) + '\tools\oggenc2.exe';
  end;

end;

procedure TMainForm.SetPanelState(const EncoderIndex: integer);
begin

  case EncoderIndex of
    0:
      begin
        FAACPanel.Visible := True;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    1:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := True;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    2:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := True;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    3:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := True;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    4:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := True;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    5:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := True;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    6:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := True;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    7:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := True;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    8:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := True;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    9:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := True;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    10:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := True;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    11:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := True;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    12:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := True;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    13:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := True;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    14:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := True;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := False;
      end;
    15:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := True;
        WavPackPanel.Visible := False;
      end;
    16:
      begin
        FAACPanel.Visible := False;
        QaacPanel.Visible := False;
        AftenPanel.Visible := False;
        OggPanel.Visible := False;
        LamePanel.Visible := False;
        WavePanel.Visible := False;
        FLACPanel.Visible := False;
        FHGPanel.Visible := False;
        OpusPanel.Visible := False;
        MPCPanel.Visible := False;
        MACPanel.Visible := False;
        TTAPanel.Visible := False;
        TAKPanel.Visible := False;
        NeroPanel.Visible := False;
        AlacPanel.Visible := False;
        WMAPanel.Visible := False;
        WavPackPanel.Visible := True;
      end;
  end;

  AudioCodecBtn.Visible := False;
  AudioCodecBtn.Visible := True;

end;

procedure TMainForm.SettingsBtnClick(Sender: TObject);
begin

  Self.Enabled := False;
  SettingsForm.show;

end;

function TMainForm.ShutDown(RebootParam: Longword): Boolean;
var
  TTokenHd: THandle;
  TTokenPvg: TTokenPrivileges;
  cbtpPrevious: DWORD;
  rTTokenPvg: TTokenPrivileges;
  pcbtpPreviousRequired: DWORD;
  tpResult: Boolean;
const
  SE_SHUTDOWN_NAME = 'SeShutdownPrivilege';
begin
  if Win32Platform = VER_PLATFORM_WIN32_NT then
  begin
    tpResult := OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or
      TOKEN_QUERY, TTokenHd);
    if tpResult then
    begin
      tpResult := LookupPrivilegeValue(nil, SE_SHUTDOWN_NAME,
        TTokenPvg.Privileges[0].Luid);
      TTokenPvg.PrivilegeCount := 1;
      TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      cbtpPrevious := SizeOf(rTTokenPvg);
      pcbtpPreviousRequired := 0;
      if tpResult then
        AdjustTokenPrivileges(TTokenHd, False, TTokenPvg, cbtpPrevious,
          rTTokenPvg, pcbtpPreviousRequired);
    end;
  end;
  Result := ExitWindowsEx(RebootParam, 0);

end;

procedure TMainForm.sLabel2Click(Sender: TObject);
begin
  if FileExists(AppFolder + '\Tools\fhgaacenc\Readme.txt') then
  begin

    ShellExecute(Application.Handle, 'open',
      PChar(AppFolder + '\Tools\fhgaacenc\Readme.txt'), nil, nil,
      SW_SHOWNORMAL);
  end;
end;

procedure TMainForm.sLabel3Click(Sender: TObject);
begin
  ShellExecute(Application.Handle, 'open',
    'http://lame.cvs.sourceforge.net/viewvc/lame/lame/USAGE', nil, nil,
    SW_SHOWNORMAL);
end;

function TMainForm.SoXPercentage(const SoxOutput: string): Integer;
begin

  if (Length(SoxOutput) > 0) then
  begin

    if Copy(SoxOutput, 3, 3) = '100' then
    begin
      Result := 100;
    end
    else if IsStringNumeric(Copy(SoxOutput, 3, 2)) then
    begin
      Result := StrToInt(Copy(SoxOutput, 3, 2));
    end;

  end;

end;

procedure TMainForm.StartBtnClick(Sender: TObject);
var
  i, j: Integer;
  AdvancedOptions: string;
  NumberOfProcesses: integer;
  CommandPerProcess: integer;
  LastProcessCommand: integer;

begin

  if FileList.Items.Count > 0 then
  begin

    if not DirectoryExists(SettingsForm.TempEdit.Text) then
    begin
      if not CreateDir(SettingsForm.TempEdit.Text) then
      begin
        Application.MessageBox('Cannot find and create temp folder!', 'Error',
          MB_ICONERROR);
        Exit;
      end;
    end;

    if not SameAsSourceBtn.Checked then
    begin
      if not DirectoryExists(DirectoryEdit.Text) then
      begin
        if not CreateDir(DirectoryEdit.Text) then
        begin
          Application.MessageBox('Cannot create output folder!', 'Error',
            MB_ICONERROR);
          Exit;
        end;
      end;
    end;

    // check nero exe
    if AudioEncoderIndex = 13 then
    begin
      if not FileExists(NeroEncPath) then
      begin
        Application.MessageBox
          ('Cannot find neroaacenc.exe. Please download it and place it in program folder.',
          'Error', MB_ICONERROR);
        Exit;
      end;
    end;

    if DirectoryExists(DirectoryEdit.Text) or SameAsSourceBtn.Checked then
    begin
      CurrentFileIndexes.Clear;
      SummaryView.Items.Clear;
      FilesToCheck.Clear;
      TimePassed := 0;
      Encoder1.ResetValues;
      Encoder2.ResetValues;
      Encoder3.ResetValues;
      Encoder4.ResetValues;
      Encoder5.ResetValues;
      Encoder6.ResetValues;
      Encoder7.ResetValues;
      Encoder8.ResetValues;
      TotalCMDCount := 0;
      TotalLength := 0;

      Self.Caption := 'Encoding [TAudioConverter]';

      DeleteTempFiles();
      DisableUI;

      // decide number of processes
      if (SettingsForm.ProcessCountList.ItemIndex + 1) > FileList.Items.Count
      then
      begin
        NumberOfProcesses := FileList.Items.Count;
      end
      else
      begin
        NumberOfProcesses := SettingsForm.ProcessCountList.ItemIndex + 1;
      end;

      if NumberOfProcesses >= SystemInfo.CPU.ProcessorCount then
      begin
        AddToLog(0, '');
        AddToLog(0,
          'Specified process count is too high. This can cause problems. Please consider lowering it. ');
        AddToLog(0, '');
      end;

      CommandPerProcess := Round(FileList.Items.Count / NumberOfProcesses);
      if (NumberOfProcesses * CommandPerProcess) = FileList.Items.Count then
      begin
        LastProcessCommand := 0;
      end
      else if (NumberOfProcesses * CommandPerProcess) < FileList.Items.Count
      then
      begin
        LastProcessCommand := FileList.Items.Count -
          (NumberOfProcesses * CommandPerProcess);
      end
      else if (NumberOfProcesses * CommandPerProcess) > FileList.Items.Count
      then
      begin
        LastProcessCommand := CommandPerProcess +
          (FileList.Items.Count - (NumberOfProcesses * CommandPerProcess));

        if LastProcessCommand < 0 then
        begin
          LastProcessCommand := 0;
        end;
      end;

      Self.Enabled := False;
      try

        Self.Caption := 'Creating commands';

        // addcommandline fileindex, advanced settings, encoder index
        for I := 0 to FileList.Items.Count - 1 do
        begin
          Application.ProcessMessages;

          AddCommandLine(i, AdvancedOptions, (i mod NumberOfProcesses) + 1);
        end;

        // add process info to log
        AddToLog(0, '');
        AddToLog(0, 'Number of commands per process are as follows:');
        AddToLog(0, 'Encoder1: ' + FloatToStr(Encoder1.CommandLines.Count));
        AddToLog(0, 'Encoder2: ' + FloatToStr(Encoder2.CommandLines.Count));
        AddToLog(0, 'Encoder3: ' + FloatToStr(Encoder3.CommandLines.Count));
        AddToLog(0, 'Encoder4: ' + FloatToStr(Encoder4.CommandLines.Count));
        AddToLog(0, 'Encoder5: ' + FloatToStr(Encoder5.CommandLines.Count));
        AddToLog(0, 'Encoder6: ' + FloatToStr(Encoder6.CommandLines.Count));
        AddToLog(0, 'Encoder7: ' + FloatToStr(Encoder7.CommandLines.Count));
        AddToLog(0, 'Encoder8: ' + FloatToStr(Encoder8.CommandLines.Count));
        AddToLog(0, '');

      finally
        Self.Enabled := True;
        Self.Caption := 'Encoding [TAudioConverter]';
      end;

      // add commandlines to the log
      AddToLog(0, '--------------------------------------------');
      AddToLog(0, 'Starting encoding process');
      AddToLog(0, 'Command lines:');
      for I := 0 to Encoder1.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder1.CommandLines[i]);
      end;
      for I := 0 to Encoder2.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder2.CommandLines[i]);
      end;
      for I := 0 to Encoder3.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder3.CommandLines[i]);
      end;
      for I := 0 to Encoder4.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder4.CommandLines[i]);
      end;
      for I := 0 to Encoder5.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder5.CommandLines[i]);
      end;
      for I := 0 to Encoder6.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder6.CommandLines[i]);
      end;
      for I := 0 to Encoder7.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder7.CommandLines[i]);
      end;
      for I := 0 to Encoder8.CommandCount - 1 do
      begin
        Application.ProcessMessages;
        AddToLog(0, Encoder8.CommandLines[i]);
      end;
      AddToLog(0, '--------------------------------------------');
      AddToLog(0, '');

      // calculate number of processes
      TotalCMDCount := Encoder1.CommandCount + Encoder2.CommandCount +
        Encoder3.CommandCount + Encoder4.CommandCount + Encoder5.CommandCount +
        Encoder6.CommandCount + Encoder7.CommandCount + Encoder8.CommandCount;

      if TotalCMDCount > 0 then
      begin
        FileIndex := 0;
        DurationIndex := 0;
        LastPercent := 0;
        StoppedByUser := False;
        FillSummaryList();
        FillProgressList();
        TotalProgressBar.Suffix := '% 0 of 0 so far';
        TotalProgressBar.MaxValue := TotalCMDCount;
        LaunchProcesses(NumberOfProcesses);

        PositionTimer.Enabled := True;
        Timer.Enabled := True;
        SetProgressState(Self.Handle, tbpsNormal);
      end
      else
      begin
        Application.MessageBox
          ('No commands created. This may be due to invalid source files.',
          'Error', MB_ICONERROR);
      end;

    end
    else
    begin
      Application.MessageBox('Output folder does not exist!', 'Error',
        MB_ICONERROR);
    end;

  end
  else
  begin
    Application.MessageBox('Add files first!', 'Error', MB_ICONERROR);
  end;

end;

procedure TMainForm.StopBtnClick(Sender: TObject);
begin

  if ID_YES = Application.MessageBox('Stop encoding?', 'Stop',
    MB_ICONQUESTION or MB_YESNO) then
  begin
    Encoder1.Stop;
    Encoder2.Stop;
    Encoder3.Stop;
    Encoder4.Stop;
    Encoder5.Stop;
    Encoder6.Stop;
    Encoder7.Stop;
    Encoder8.Stop;

    EnableUI;

    DeleteTempFiles();

    Self.Caption := 'TAudioConverter';

    TotalProgressBar.Progress := 0;
    SetProgressValue(Self.Handle, 0, 100);
    SetProgressState(Self.Handle, tbpsNone);
    PositionTimer.Enabled := False;
    Timer.Enabled := False;
    TimePassed := 0;
    TimePassedLabel.Caption := 'Time Passed: 00:00:00';
    TotalProgressBar.Suffix := '% 0 of 0 so far';

    SaveLogs;

    // post-encode action
    case PostEncodeList.ItemIndex of
      0:
        begin

        end;
      1:
        begin
          // Application.Terminate;
        end;
      2:
        begin
          OutputBtn.OnClick(Self);
        end;
    end;
  end;

end;

function TMainForm.SubStringOccurences(const subString,
  sourceString: string): integer;
var
  pEx: integer;
begin
  Result := 0;
  pEx := PosEx(subString, sourceString, 1);
  while pEx <> 0 do
  begin
    Inc(Result);
    pEx := PosEx(subString, sourceString, pEx + Length(subString));
  end;
end;

procedure TMainForm.TAEncTTA1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 11;
  SetPanelState(AudioEncoderIndex);
end;

function TMainForm.TAKPercentage(const TAKOutput: string): integer;
var
  StrPos1, StrPos2: integer;
  TmpStr: string;
begin

  if Length(TAKOutput) > 0 then
  begin
    StrPos1 := Pos('wav', TAKOutput);
    StrPos2 := Pos('%', TAKOutput);

    TmpStr := Trim(Copy(TAKOutput, StrPos1 + 3, MAXINT));
    if Length(TmpStr) > 0 then
    begin
      Result := SubStringOccurences('.', TmpStr) * 10;
    end;
  end;

end;

procedure TMainForm.TimerTimer(Sender: TObject);
begin

  Inc(TimePassed);
  TimePassedLabel.Caption := 'Time Passed: ' + IntToTime(TimePassed);

end;

function TMainForm.TimeToInt(const TimeStr: string): Integer;
var
  TimeList: TStringList;
  hour: Integer;
  minute: Integer;
  second: Integer;
begin

  if Length(TimeStr) = 8 then
  begin

    TimeList := TStringList.Create;
    try
      TimeList.Delimiter := ':';
      TimeList.StrictDelimiter := True;
      TimeList.DelimitedText := TimeStr;

      hour := 0;
      minute := 0;
      second := 0;

      if TimeList.Count = 3 then
      begin

        if IsStringNumeric(TimeList[0]) then
        begin
          hour := StrToInt(TimeList[0]);
        end;

        if IsStringNumeric(TimeList[1]) then
        begin
          minute := StrToInt(TimeList[1]);
        end;

        if IsStringNumeric(TimeList[2]) then
        begin
          second := StrToInt(TimeList[2]);
        end;

        Result := (hour * 3600) + (minute * 60) + second;

      end;

    finally
      FreeAndNil(TimeList);
    end;

  end;

end;

procedure TMainForm.TrayIconBalloonClick(Sender: TObject);
begin
  TrayIcon.Active := False;
end;

procedure TMainForm.TrayIconClick(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  TrayIcon.Active := False;
end;

procedure TMainForm.TrayIconDblClick(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  TrayIcon.Active := False;
end;

procedure TMainForm.UpBtnClick(Sender: TObject);
var
  i: Integer;
begin

  for i := 0 to FileList.Items.Count - 1 do
  begin

    if i > 0 then
    begin

      if FileList.Selected[i] then
      begin
        FileList.Items.Exchange(i, i - 1);
        FileList.Selected[i - 1] := True;
        Durations.Exchange(i, i - 1);
        AudioTracks.Exchange(i, i - 1);
        AudioIndexes.Exchange(i, i - 1);
        Files.Exchange(i, i - 1);
        ExtensionsForCopy.Exchange(i, i - 1);
        CopyExtension.Exchange(i, i - 1);
      end;

    end;

  end;

end;

procedure TMainForm.UpdateBtnClick(Sender: TObject);
begin

  Self.Enabled := False;
  UpdaterForm.show;

end;

procedure TMainForm.UpdateCheckerDoneFile(Sender: TObject; FileName: string;
  FileSize: Integer; Url: string);
var
  VersionFile: TStringList;
  LatestVersion: Integer;
begin

  VersionFile := TStringList.Create;
  try

    if FileExists(FileName) then
    begin
      VersionFile.LoadFromFile(FileName);

      if VersionFile.Count = 1 then
      begin

        if IsStringNumeric(VersionFile.Strings[0]) then
        begin
          LatestVersion := StrToInt(VersionFile.Strings[0]);

          if LatestVersion > BuildInt then
          begin

            if ID_YES = Application.MessageBox
              ('There is a new version. Would you like to go homepage and download it?',
              'New Version', MB_ICONQUESTION or MB_YESNO) then
            begin
              ShellExecute(Application.Handle, 'open',
                'http://taudioconverter.sourceforge.net/', nil, nil,
                SW_SHOWNORMAL);
            end;

          end;

        end;

      end;
    end;

  finally
    FreeAndNil(VersionFile);
  end;

end;

procedure TMainForm.UpdateListboxScrollBox(ListBox: TsListBox);
var
  j: Integer;
  MaxWidth: Integer;
begin

  MaxWidth := 0;

  for j := 0 to ListBox.Items.Count - 1 do
  begin

    if MaxWidth < ListBox.Canvas.TextWidth(ListBox.Items[j]) then
    begin
      MaxWidth := ListBox.Canvas.TextWidth(ListBox.Items[j]);
    end;

  end;

  SendMessage(ListBox.Handle, LB_SETHORIZONTALEXTENT, MaxWidth + 5, 0);
end;

function TMainForm.UpdateProgressUI: integer;
var
  TotalProgress: integer;
begin

  TotalProgress := Encoder1.FilesDone + Encoder2.FilesDone + Encoder3.FilesDone
    + Encoder4.FilesDone + Encoder5.FilesDone + Encoder6.FilesDone +
    Encoder7.FilesDone + Encoder8.FilesDone;

  if AudioEncoderIndex = 5 then
  begin
    TotalProgressBar.Progress := TotalProgress;
    TotalProgressBar.Suffix := '% ' + FloatToStr(TotalProgress) + ' of ' +
      FloatToStr(TotalCMDCount) + ' so far';
  end
  else
  begin
    TotalProgressBar.Progress := TotalProgress;
    TotalProgressBar.Suffix := '% ' + FloatToStr(TotalProgress) + ' of ' +
      FloatToStr(TotalCMDCount) + ' so far';
  end;

  if (Encoder1.EncoderStatus = esStopped) or (Encoder1.EncoderStatus = esDone)
  then
  begin
    ProgressBar1.Suffix := '%';
    ProgressBar1.Progress := 0;
  end
  else
  begin
    ProgressBar1.Suffix := '% ' + sLineBreak + Encoder1.Info + ': ' +
      ExtractFileName(Encoder1.CurrentFile);

    ProgressBar1.Progress := GetPercentage(1);
  end;

  if (Encoder2.EncoderStatus = esStopped) or (Encoder2.EncoderStatus = esDone)
  then
  begin
    ProgressBar2.Suffix := '%';
    ProgressBar2.Progress := 0;
  end
  else
  begin
    ProgressBar2.Suffix := '% ' + Encoder2.Info + ': ' +
      ExtractFileName(Encoder2.CurrentFile);

    ProgressBar2.Progress := GetPercentage(2);
  end;

  if (Encoder3.EncoderStatus = esStopped) or (Encoder3.EncoderStatus = esDone)
  then
  begin
    ProgressBar3.Suffix := '%';
    ProgressBar3.Progress := 0;
  end
  else
  begin
    ProgressBar3.Suffix := '% ' + Encoder3.Info + ': ' +
      ExtractFileName(Encoder3.CurrentFile);

    ProgressBar3.Progress := GetPercentage(3);
  end;

  if (Encoder4.EncoderStatus = esStopped) or (Encoder4.EncoderStatus = esDone)
  then
  begin
    ProgressBar4.Suffix := '%';
    ProgressBar4.Progress := 0;
  end
  else
  begin
    ProgressBar4.Suffix := '% ' + Encoder4.Info + ': ' +
      ExtractFileName(Encoder4.CurrentFile);

    ProgressBar4.Progress := GetPercentage(4);
  end;

  if (Encoder5.EncoderStatus = esStopped) or (Encoder5.EncoderStatus = esDone)
  then
  begin
    ProgressBar5.Suffix := '%';
    ProgressBar5.Progress := 0;
  end
  else
  begin
    ProgressBar5.Suffix := '% ' + Encoder5.Info + ': ' +
      ExtractFileName(Encoder5.CurrentFile);

    ProgressBar5.Progress := GetPercentage(5);
  end;

  if (Encoder6.EncoderStatus = esStopped) or (Encoder6.EncoderStatus = esDone)
  then
  begin
    ProgressBar6.Suffix := '%';
    ProgressBar6.Progress := 0;
  end
  else
  begin
    ProgressBar6.Suffix := '% ' + Encoder6.Info + ': ' +
      ExtractFileName(Encoder6.CurrentFile);

    ProgressBar6.Progress := GetPercentage(6);
  end;

  if (Encoder7.EncoderStatus = esStopped) or (Encoder7.EncoderStatus = esDone)
  then
  begin
    ProgressBar7.Suffix := '%';
    ProgressBar7.Progress := 0;
  end
  else
  begin
    ProgressBar7.Suffix := '% ' + Encoder7.Info + ': ' +
      ExtractFileName(Encoder7.CurrentFile);

    ProgressBar7.Progress := GetPercentage(7);
  end;

  if (Encoder8.EncoderStatus = esStopped) or (Encoder8.EncoderStatus = esDone)
  then
  begin
    ProgressBar8.Suffix := '%';
    ProgressBar8.Progress := 0;
  end
  else
  begin
    ProgressBar8.Suffix := '% ' + Encoder8.Info + ': ' +
      ExtractFileName(Encoder8.CurrentFile);
    ProgressBar8.Progress := GetPercentage(8);
  end;

  Result := TotalProgress;
end;

procedure TMainForm.UpdateThreadExecute(Sender: TObject; Params: Pointer);
begin

  with UpdateChecker do
  begin
    Url := 'http://dl.dropbox.com/u/9617171/TAudioConverter.txt';
    FileName := SystemInfo.Folders.Temp + '\TAudioConverter\version.txt';
    Start;
  end;

  UpdateThread.CancelExecute;

end;

function TMainForm.WMAEncoderPercentage(const WMAOutput: string): integer;
var
  TmpStr: string;
begin
  // Start encoding...
  if Length(WMAOutput) > 0 then
  begin
    TmpStr := WMAOutput;
    TmpStr := ReplaceText(TmpStr, 'Start encoding...', '');
    TmpStr := Trim(ReplaceStr(TmpStr, '%', ''));

    if IsStringNumeric(TmpStr) then
    begin
      Result := StrToInt(TmpStr);
    end;
  end;
end;

procedure TMainForm.WMAEncodeWMA1Click(Sender: TObject);
begin

  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 15;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.WMAMethodListChange(Sender: TObject);
begin

  WMAQualityList.Enabled := WMAMethodList.ItemIndex = 0;
  WMABitrateEdit.Enabled := not WMAQualityList.Enabled;

end;

procedure TMainForm.WMCopyData(var Message: TWMCopyData);
var
  Arg: string;
begin
  SetString(Arg, PChar(Message.CopyDataStruct.lpData),
    (Message.CopyDataStruct.cbData div SizeOf(Char)) - 1);

  // check if timer is enabled.
  // if it is, then reject new files.
  if not PositionTimer.Enabled then
  begin
    AddFile(Arg, False);

    if FileExists(Arg) then
    begin
      LastDirectory := ExtractFileDir(Arg);
    end;

    UpdateListboxScrollBox(FileList);
  end;
  Application.Restore;
  Application.BringToFront;

end;

procedure TMainForm.WriteLnToFile(const FileName, Line: string);
var
  TF: TextFile;
begin

  {if file alread exists append line to it.
   else create it.}

  if FileExists(FileName) then
  begin
    AssignFile(TF, FileName);
    Append(TF);
    try
      Writeln(TF, Line);
    finally
      CloseFile(TF);
    end;
  end
  else
  begin
    AssignFile(TF, FileName);
    Rewrite(TF);
    try
      Writeln(TF, Line);
    finally
      CloseFile(TF);
    end;
  end;

end;

function TMainForm.x264Percentage(const x264Output: string): Integer;
var
  TmpStr: string;
  TmpInt: Integer;
  FConsoleOutput: string;
  StrPos: Integer;
begin

  Result := 0;

  FConsoleOutput := Trim(x264Output);

  if Length(FConsoleOutput) > 0 then
  begin

    if Copy(FConsoleOutput, 1, 1) = '[' then
    begin
      StrPos := Pos('%]', FConsoleOutput);

      if StrPos > -1 then
      begin
        TmpStr := Copy(FConsoleOutput, 2, StrPos);
        Delete(TmpStr, Length(TmpStr) - 3, 4);

        if TryStrToInt(TmpStr, TmpInt) then
        begin
          Result := TmpInt;
        end;

      end;

    end;

  end;

end;

procedure TMainForm.QAACAAC1Click(Sender: TObject);
begin
  AudioCodecBtn.Caption := (Sender as TMenuItem).Caption;
  AudioEncoderIndex := 1;
  SetPanelState(AudioEncoderIndex);
end;

procedure TMainForm.QaacEncodeMethodListChange(Sender: TObject);
begin

  if QaacEncodeMethodList.ItemIndex = 1 then
  begin
    QaacvQualityEdit.Enabled := True;
    QaacBitrateEdit.Enabled := False;
  end
  else
  begin
    QaacvQualityEdit.Enabled := False;
    QaacBitrateEdit.Enabled := True;
  end;

  if QaacHEBtn.Checked then
  begin

    if QaacEncodeMethodList.ItemIndex = 1 then
    begin
      Application.MessageBox('TVBR is not available with HE AAC mode.',
        'Warning', MB_ICONWARNING);
      QaacHEBtn.Checked := False;
    end;

  end;

end;

procedure TMainForm.QaacHEBtnClick(Sender: TObject);
begin

  if QaacHEBtn.Checked then
  begin

    if QaacEncodeMethodList.ItemIndex = 1 then
    begin
      Application.MessageBox('TVBR is not available with HE AAC mode.',
        'Warning', MB_ICONWARNING);
      QaacHEBtn.Checked := False;
    end;

  end;

end;

end.
